模型活页夹中的填充实体与替换活页夹的外部方法

Filling entity in model binder vs external method that replace binder

我有 asp.net MVC 网络应用程序。它是一些实体的列表,用户可以在其中选择其中的一些实体并查看详细信息等。

此应用程序的大部分操作都有一些 Entity 作为参数。例如:

[Authorize]
public ActionResult Details(Entity entity)
{
    ...
    return View();
}

我将此实体保留在会话中,并通过 URL 中的 ID 将此参数填充到模型活页夹中。看起来像:

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    var httpContext = controllerContext.HttpContext;
    var values = httpContext.Request.RequestContext.RouteData.Values;

    if (!values.ContainsKey("id")) return null;

    var id = values["id"].ToString();
    var obj = httpContext.Session["Entities"];
    var list =  (List<Entity>) obj;
    return list?.SingleOrDefault(x => x.Id == id);
}

但有时可能会出现用户在会话对象为空时尝试访问操作的情况。例如,用户通过电子邮件获得 URL 操作并省略将实体置于会话中的代码。

这种情况的最佳解决方法是什么?

1.在活页夹中实现获取实体:

    var id = values["id"].ToString();
    var obj = httpContext.Session["Entities"];
    var list =  (List<Entity>) obj;
    var entity = list?.SingleOrDefault(x => x.Id == id);

    if(null==entity){
        entity = repository.GetEntity(id);
        //set entity in session
    }

    return entity; 

这种方式看起来很糟糕,因为我必须在活页夹中实现额外的填充逻辑。另外,我无法在活页夹中注入存储库。但是这种方式简单易行

2。删除活页夹并添加一些获取方法:

完全删除活页夹,并通过以下方式更改实体的所有操作:

[Authorize]
public ActionResult Details()
{
    Entity entity = GetEntity();
    ...
    return View();
}
private Entity GetEntity()
{
    var id = ... //get id from http request.
    var list = (List<Entity>)Session["Entities"];
    var entity = list?.SingleOrDefault(x => x.Id == id);

    if(null==entity){
        entity = repository.GetEntity(id);
        //set entity in session
    }

    return entity; 
}

我现在可以实现仓库注入了,代码是安全的,但是看起来很丑

哪种解决方案最好?有没有可能我错过了任何其他实施?

This way looks nasty because of I have to implement extra filling logic in the binder. Also, I can't inject repository in the binder.

您说得对,依赖注入无法在模型绑定器中正确完成。但是你可以使用工厂:

public class MyModelBinder : DefaultModelBinder
{
    private readonly Func<IRepository> repositoryProvider;

    public MyModelBinder(Func<IRepository> repositoryProvider)
    {
        this.repositoryProvider = repositoryProvider;
    }

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var id = ... //get id from http request.
        var list = (List<Entity>)Session["Entities"];
        var entity = list?.SingleOrDefault(x => x.Id == id);

        if (null == entity)
        {
            IRepository repository = this.repositoryProvider();
            entity = repository.GetEntity(id);
            //set entity in session
        }

        return entity; 
    }
}

然后在注册您的活页夹时:

ModelBinders.Binders[typeof(Entity)] = new MyModelBinder(
    () => DependencyResolver.Current.GetService<IRepository>()
);