Asp.net mvc 4 何时要在IModelBinder上使用IDependencyResolver?
创建新项后,当将表单中的信息发布回控制器时,它表示找不到无参数构造函数。这是预期的,因为用作视图模型的视图模型依赖于域模型对象 然后我决定写我自己的模型活页夹 NewItemViewModelBinderAsp.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
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;
}
它不起作用,我遇到了与无参数构造函数相同的问题
所以,我有三个问题
作为开发人员,我们总是试图尽可能地概括设计,毕竟,这通常是最好的做法。然而,当涉及到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依赖项,则控制器负责清理它们。