Automatically Pass Entity to Controller Action Object

When adding a controller for the model, the created actions will look something like this:

public ActionResult Edit(int id = 0)
{
    Entity entity = db.Entities.Find(id);
    if (entity == null)
    {
        return HttpNotFound();
    }
    return View(entity);
}

Now, in my case, I take a string identifier that can be mapped to database identifiers in several ways , creating several lines of code to retrieve the correct entity. Copying and pasting this code into every action that takes an identifier to receive an object feels very inelegant.

Entering the search code in a private controller function reduces the number of duplicate code, but I still remain with this:

var entity = GetEntityById(id);
if (entity == null)
    return HttpNotFound();

? python, . - WCF, IOperationBehavior, - . - , , , , .

:

[EntityLookup(id => db.Entities.Find(id))]
public ActionResult Edit(Entity entity)
{
    return View(entity);
}

EntityLookup string id Entity HttpNotFound, .

+5
2

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 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 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 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);
}
+3

, .

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);
    }
}
0

All Articles