自动将实体传递到控制器操作
本文关键字:控制器 操作 实体 | 更新日期: 2023-09-27 18:00:54
为模型添加控制器时,生成的操作将如下所示
public ActionResult Edit(int id = 0)
{
Entity entity = db.Entities.Find(id);
if (entity == null)
{
return HttpNotFound();
}
return View(entity);
}
现在,在我的例子中,我采用一个字符串 id,它可以通过多种方式映射到数据库 ID,生成几行代码来检索正确的实体。将该代码复制并粘贴到每个使用 id 来检索实体的操作中感觉非常不优雅。
将检索代码放在控制器的私有函数中可以减少重复代码的数量,但我仍然留下这个:
var entity = GetEntityById(id);
if (entity == null)
return HttpNotFound();
有没有办法在属性中执行查找并将实体传递给操作?来自python,这可以通过装饰器轻松实现。我设法通过实现一个仍然感觉不那么简单的IOperationBehavior
为 WCF 服务做了类似的事情。由于按 id 检索实体是您经常需要做的事情,我希望除了复制和粘贴代码之外还有其他方法。
理想情况下,它看起来像这样:
[EntityLookup(id => db.Entities.Find(id))]
public ActionResult Edit(Entity entity)
{
return View(entity);
}
其中EntityLookup
采用任意函数映射string id
Entity
,并返回HttpNotFound
或使用检索到的实体作为参数调用操作。
您可以编写一个自定义 ActionFilter:
public class EntityLookupAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// retrieve the id parameter from the RouteData
var id = filterContext.HttpContext.Request.RequestContext.RouteData.Values["id"] as string;
if (id == null)
{
// There was no id present in the request, no need to execute the action
filterContext.Result = new HttpNotFoundResult();
}
// we've got an id, let's query the database:
var entity = db.Entities.Find(id);
if (entity == null)
{
// The entity with the specified id was not found in the database
filterContext.Result = new HttpNotFoundResult();
}
// We found the entity => we could associate it to the action parameter
// let's first get the name of the action parameter whose type matches
// the entity type we've just found. There should be one and exactly
// one action argument that matches this query, otherwise you have a
// problem with your action signature and we'd better fail quickly here
string paramName = filterContext
.ActionDescriptor
.GetParameters()
.Single(x => x.ParameterType == entity.GetType())
.ParameterName;
// and now let's set its value to the entity
filterContext.ActionParameters[paramName] = entity;
}
}
然后:
[EntityLookup]
public ActionResult Edit(Entity entity)
{
// if we got that far the entity was found
return View(entity);
}
如果要重复类似的代码,则可以使用扩展方法。
public static class ControllerExtensions
{
public static ActionResult StandardEdit<TEntity>(
this Controller controller,
DbContext db,
long id)
where TEntity : class
{
TEntity entity = db.Set<TEntity>().Find(id);
if (entity == null)
{
return controller.HttpNotFound();
}
return controller.View(entity);
}
}
public ActionResult Edit(long id = 0)
{
return this.StandardEdit<Client>(db, id);
}
如果您确实多次重复完全相同的代码,那么这应该通过继承来解决。
创建继承自Controller
的通用控制器
public class StandardController : Controller
{
public ActionResult Edit<TEntity>(long id = 0)
where TEntity : class
{
TEntity entity = db.Set<TEntity>().Find(id);
if (entity == null)
{
return HttpNotFound();
}
return View(entity);
}
}
并将模型控制器更改为从此新控制器继承:
public class ClientController : StandardController
{
public ActionResult Edit(long id = 0)
{
return base.Edit<Client>(id);
}
}