什么时候想在IModelBinder上使用IDependencyResolver?

时间:2015-02-08 21:19:59

标签: asp.net-mvc-4 dependency-injection ninject modelbinders dependency-resolver

创建新项目后,将表单中的信息发布回控制器时,表示无法找到无参数构造函数。这是预期的,因为用作视图模型的视图模型取决于域模型对象。

然后我决定编写自己的模型装订器。

NewItemViewModelBinder

public class NewItemViewModelBinder : DefaultModelBinder {
    public NewItemViewModelBinder(IKernel kernel) {
        if (kernel == null) throw new ArgumentNullException("kernel");
        this.kernel = kernel;
    }

    protected override object CreateModel(ControllerContext controllerContext
        , ModelBindingContext bindingContext, Type modelType) {
        return kernel.Get(modelType);
    }

    private readonly IKernel kernel;
}

使用模型绑定器的这个解决方案在将此绑定器注册到NinjectWebCommon.RegisterServices方法中的ModelBinders.Binder时工作得很好。

public void RegisterServices(IKernel kernel) {
    CompositionRoot.ComposeObjectGraph();
    ModelBinders
        .Binders
        .Add(typeof(NewItemViewModel), new NewItemViewModelBinder(kernel));
}

此外,我还发现了其他一些谈论DependencyResolver的帖子。所以我认为如果我能编写一个可以解决所有其他创建问题的依赖解析器,那么我就可以解决其余问题。

NinjectDependencyResolver

public class NinjectDependencyResolver : NinjectDependencyScope
    : System.Web.Http.Dependencies.IDependencyResolver
    , System.Web.Mvc.IDependencyResolver {
    public NinjectDepencyResolver(IKernel kernel
        , IDependencyScopeFactory factory) : base(kernel) {
        if (kernel == null) throw new ArgumentNullException("kernel");
        if (factory == null) throw new ArgumentNullException("factory");
        this.kernel = kernel;
    }

    public IDependencyScope BeginScope() { 
        return factory.Create(kernel.BeginBlock()); 
    }

    public object GetService(Type serviceType) {
        return kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType) {
        return kernel.GetAll(serviceType);
    }

    public void Dispose() { base.Dispose(); }

    private readonly IKernel kernel;
    private readonly IDependencyScopeFactory factory;
}

将此新解析程序设置为MVC的依赖项解析程序后,

DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));

它没有用,我遇到了与无参数构造函数相同的问题。

所以,我有三个问题。

  1. 我对DependencyResolver方法做了什么错误?
  2. 使用DependencyResolver与ModelBinder有什么好处?
  3. 何时使用其中任何一个?

1 个答案:

答案 0 :(得分:2)

根据Wrox Professional ASP.NET MVC 4,第308页,您不应将IDependencyResolver用于您的应用程序。

  

你应该在你的消费者中消费依赖性   应用?   您可能想要从自己的内部使用IDependencyResolver   应用。抵制那种诱惑。   依赖解析器接口正是MVC所需要的 - 什么也没有   更多。它无意隐藏或替换您的依赖项的传统API   注射容器。大多数容器都有复杂而有趣的API;事实上,它是   您可能会根据API和功能选择容器   提供比任何其他原因更多。

IDependencyResolver旨在为MVC框架提供依赖项,而不是应用程序。

IDependencyResolver的实现方式遵循service locator (anti-)pattern

此外,IDependencyResolver不需要将DI与MVC一起使用。更好的选择是使用IControllerFactory将依赖项注入控制器并使用其他扩展点(例如IModelBinder),使用构造函数注入,而不是服务位置。

至于使用IModelBinder,你正在对你的例子使用一个很好的做法,因为你正在进行构造函数注入(尽管有些人可能认为模型不应该有依赖关系,但这取决于你的框架设计)。

作为开发人员,我们总是尽可能地尝试概括设计,毕竟,这通常是最好的行动方案。但是,谈到DI,我们必须打击这种冲动。对于DI,最好让每个类按类型明确地询问它自己的依赖项,这样很明显类需要什么才能运行。服务定位器处于这一范围的另一端 - 它是一个黑盒服务,可能包含也可能不包含应用程序运行所需的所有类型,这使得应用程序更难配置。