CreateModel的一个自定义模型绑定器和BindModel的另一个自定义模型绑定器?

时间:2012-02-18 16:03:26

标签: asp.net-mvc inversion-of-control model-binding custom-model-binder

背景 在我的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?或者有人知道更好的方法吗?

1 个答案:

答案 0 :(得分:1)

您可以在原始模型绑定器中使用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);
    }
}