Asp.net mvc 4 何时要在IModelBinder上使用IDependencyResolver?

Asp.net mvc 4 何时要在IModelBinder上使用IDependencyResolver?,asp.net-mvc-4,dependency-injection,ninject,modelbinders,dependency-resolver,Asp.net Mvc 4,Dependency Injection,Ninject,Modelbinders,Dependency Resolver,创建新项后,当将表单中的信息发布回控制器时,它表示找不到无参数构造函数。这是预期的,因为用作视图模型的视图模型依赖于域模型对象 然后我决定写我自己的模型活页夹 NewItemViewModelBinder public class NewItemViewModelBinder : DefaultModelBinder { public NewItemViewModelBinder(IKernel kernel) { if (kernel == null) throw ne

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

然后我决定写我自己的模型活页夹

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;
}
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;
}
在NinjectWebCommon.RegisterServices方法中将此绑定器注册到ModelBinders.Binders之后,此带有模型绑定器的解决方案工作得很好

public void RegisterServices(IKernel kernel) {
    CompositionRoot.ComposeObjectGraph();
    ModelBinders
        .Binders
        .Add(typeof(NewItemViewModel), new NewItemViewModelBinder(kernel));
}
除此之外,我还看到了其他一些关于DependencyResolver的帖子。所以我想如果我能写一个依赖解析程序来解决所有其他的创建问题,那么我就不会有其他的麻烦了

NinjectDependencyResolver

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;
}
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;
}
它不起作用,我遇到了与无参数构造函数相同的问题

所以,我有三个问题

  • 我对DependencyResolver方法做了什么错误
  • 与ModelBinder相比,使用DependencyResolver有哪些好处
  • 何时使用其中一种
  • 根据第308页的说明,您不应该在应用程序中使用IDependencyResolver

    您是否应该在应用程序中使用DEPENDENCYRESOLVER 应用 您可能会试图从自己的内部使用IDependencyResolver 应用抵制这种诱惑。 依赖解析程序接口正是MVC所需要的,而不是什么 更多它并不打算隐藏或替换依赖项的传统API 注射容器。大多数容器都有复杂而有趣的API;事实上,它是 您很可能会根据它提供的API和功能选择容器 提供比任何其他原因都多的信息

    IDependencyResolver旨在为MVC框架而不是应用程序提供依赖关系

    IDependencyResolver的实现方式如下

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

    至于使用IModelBinder,您在示例中使用了一个良好的实践,因为您正在进行构造函数注入(尽管有些人可能认为模型不应该具有依赖性,但这取决于您的框架设计)


    作为开发人员,我们总是试图尽可能地概括设计,毕竟,这通常是最好的做法。然而,当涉及到DI时,我们必须抵制这种冲动。对于DI,最好让每个类按类型显式地请求自己的依赖项,这样就可以清楚地知道类需要什么功能。服务定位器位于这一范围的另一端-它是一个服务的黑盒,可能包含也可能不包含应用程序运行所需的所有类型,它使应用程序更难配置。

    只需在视图模型中添加一个无参数构造函数即可(引发此错误的原因是,
    DefaultModelBinder
    在内部使用
    Activator.CreateInstance
    初始化视图模型的实例,但它不能初始化,除非它具有无参数构造函数。是的,我知道这一点,并且在第一次修补时已经这样做了。此外,我讨厌修补我的代码,所以这就是问题的原因。)当充分应用DI时,使用构造函数注入的ilst是最好的。如果我要使用默认构造函数,我必须让它传递模型的一个新实例。因此,我将紧密耦合代码,这正是要避免的。如果你有一个无参数构造函数(除了现有的构造函数之外)您不必让它传递模型的新实例,
    DefaultModelBinder
    将对其进行初始化并绑定您的值我不知道IDependencyResolver使用了服务定位器反模式。感谢您提供此信息,同时也让我放心使用IModelBinder。我在我的模型中使用构造函数注入因为ViewModel与模型本身交互,所以对于一个ViewModel的存在,我认为让它依赖于我的模型是有意义的,这个模型可以包含应用程序必须向用户显示的任何内容。我怀疑的是,内核/容器应该只在合成根中使用,我想知道这样做是否好将其传递到模型绑定器中与在IControllerFactory中实现它完全相同。本质上,您使用IModelBinder作为抽象工厂来创建模型。只要您了解IControllerFactory和IModelBinder是合成根的一部分,并且您不应该随意将容器注入整个应用程序,您就可以ine。我发现围绕容器对象进行外观抽象很有帮助,既可以将应用程序与容器解耦,又可以帮助确保容器在应用程序中不被滥用。我还没有发现
    IControllerFactory
    IModelBinder
    都是合成根的一部分。事实上事实上,我将新模型绑定器注册到
    NinjectWebCommon
    App_Start类的
    RegisterServices
    中,因此我希望确保我只引用它所属的内核/容器。我将提醒其他项目的这些精度。有一篇很好的文章解释了为什么使用抽象工厂是最重要的与MVC和任何框架进行DI集成的最佳选择。请记住,IModelBinder没有发布方法,因此如果您具有IModelBinder的IDisposable依赖项,则控制器负责清理它们。