一个自定义模型绑定到CreateModel,另一个绑定到BindModel



背景:在我的MVC post-back操作方法中,我接收的是命令对象,而不是视图模型。其想法是,这些命令对象(大致相当于事务脚本)将被设置并准备在进入动作方法时执行,模型绑定器具有在执行过程中使用的设置参数:

public class MyCommand : IMyCommand
{
    // In this case Value1 and Value2 are being set by the default model binder from posted form values - wonderful :)
    public String Value1 { get; set; }
    public String Value2 { get; set; }
    public CommandResult ExecuteCommand()
    {
        // Does something awesome...
    }
}

为了使事情稍微复杂一点,我的命令对象具有依赖项(服务、存储库等),这些依赖项在它们各自的构造函数中是必需的;所以我必须创建一个自定义模型绑定器,它使用默认的DependencyResolver(已经用我的IoC容器设置好了)来构建模型对象:

public class DependencyModelBinder : DefaultModelBinder
{
    protected override Object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        return DependencyResolver.Current.GetService(modelType);
    }
}

并在Global.asax.cs中设置如下:

ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();

同样,这一切都很好,依赖项被注入构造函数,然后默认的模型绑定器接管,像往常一样设置属性。

问题:我遇到的问题是,我的所有命令对象都有一个"SessionId"GUID参数(来自cookie),他们做的第一件事就是尝试使用注入的服务从该id解析会话对象。

public class MyCommand : IMyCommand
{
    public MyCommand (ISessionRepository sessionRepository) { ... }
    public Guid SessionId { get; set; } // Set by model binder from a cookie...
    public CommandResult Execute()
    {
        Session session = SessionRepository.Get(SessionId);
        if (session == null)
            // Do something not so awesome...
    }
}

我想删除这种重复,所以我创建了第二个模型绑定器,它将负责在存储库中进行查找,这意味着我的命令对象可以直接具有Session属性(删除会话存储库的构造函数依赖项)。

public class SessionModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var sessionRepository = DependencyResolver.Current.GetService<ISessionRepository>();
        return sessionRepository.Get((Guid)controllerContext.HttpContext.Request["SessionId"]);
    }
}

我的Global.asax.cs文件现在看起来是这样的:

ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();
ModelBinders.Binders.Add(typeof(Session), new SessionModelBinder());

在单独测试了SessionModelBinder之后,我知道它是有效的。但是,当将它与DependencyModelBinder结合使用时,永远不会调用它。如何让MVC在构建模型对象时使用我的DependencyModelBinder,但在绑定它们的会话属性时让它使用我的SessionModelBinder?或者有人知道更好的方法吗?

您可以在原始模型绑定器中使用GetPropertyValue方法为Session属性提供一个值:

public class DependencyModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        return DependencyResolver.Current.GetService(modelType);
    }
    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
    {
        if (propertyDescriptor.Name == "Session")
        {
            var sessionRepository = DependencyResolver.Current.GetService<ISessionRepository>();
            return sessionRepository.Get(controllerContext.HttpContext.Request["SessionId"]);
        }
        return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
    }
}

相关内容

  • 没有找到相关文章

最新更新