[注意:我的NinjectDependencyResolver类位于此问题的底部。]
在ASP.NET MVC 4应用程序中,我有使用服务的控制器。
每个服务都有一个构造函数参数,一个IUnitOfWork接口。 EG:
public ClientService(IUnitOfWork uow){ //... }
在Global.asax.cs类中注册一个适当编写的NinjectDependencyResolver : IDependencyResolver
类,可以正确地实例化这些服务,并且一切正常。到目前为止,非常好。
但是,我有一些情况需要在其他一些代码中实例化服务,例如,在属性中。 EG:
namespace MyApp.Domain.Attributes
{
public class AuthorizeUnprocessedOnlyAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool isUnprocessed = false;
string usuario = string.Empty;
if (httpContext.User.Identity.IsAuthenticated)
{
// THIS IS THE LINE WHERE DI IS NEEDED!!
ClientService service = new ClientService();
usuario = httpContext.User.Identity.Name;
isUnprocessed = service.IsUnprocessed(usuario);
}
return isUnprocessed;
}
}
}
我的问题是这一行:
ClientService service = new ClientService();
我必须给ClientService一个无参数构造函数,如下所示:
public ClientService() : this (new UnitOfWork()) {}
这似乎完全反DI。
这样做的原因是我不确定如何在属性代码中注入依赖项。控制器由ControllerFactory实例化,所以我不知道这一点。
也就是说,我对Ninject或IDependencyResolver不太了解......
那么,我怎样才能超越'Ignorance Pattern'
?
我应该按照以下方式获取ClientService对象:
NinjectDependencyResolver ndr = new NinjectDependencyResolver();
IUnitOfWorkMR uow = ndr.Kernel.Get<IUnitOfWorkMR>();
IClientService service = new ClientService(uow);
即使第一个问题的回答是“是”,我也不太高兴:
我仍然必须实例化ClientService的实例,所以现在我必须将IClientService接口绑定到NinjectDependencyResolver类中正确构造的ClientService实例。
这我不知道该怎么办,所以这是我的第二个问题:
如何菊花链接IUnitOfWork构造参数的依赖注入以正确实例化ClientService? (请参阅我在下面注释掉的工作 - 我对它进行了评论,因为它对我来说甚至没有意义 - 我不应该创建一个新的UnitOfWork实例,我应该吗?):
namespace MyApp.Domain.Infrastructure
{
public class NinjectDependencyResolver : IDependencyResolver
{
private IKernel kernel;
public NinjectDependencyResolver()
{
kernel = new StandardKernel();
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
public IBindingToSyntax<T> Bind<T>()
{
return kernel.Bind<T>();
}
public IKernel Kernel
{
get { return kernel; }
}
private void AddBindings()
{
kernel.Bind<IUnitOfWorkMR>().To<UnitOfWorkMR>().InRequestScope();
// kernel.Bind<IClientService>().To<ClientService>().WithConstructorArgument("uow", new UnitOfWork());
}
}
}
我更正了WithConstructorArgument中的错误(它缺少参数名称)。
编辑:
在测试中,令人难以置信的事情发生了:问题1中的代码有效。对于问题2,NinjectDepenedencyResolver类中的以下更改突然释放了一个工作应用程序(这样的事情确实是罕见的乐趣):
kernel.Bind<IUnitOfWorkMR>().To<UnitOfWorkMR>().InRequestScope();
kernel.Bind<IClientService>().To<ClientService>().InRequestScope();
即,我删除了WithConstructorArgument调用。据推测,Ninject有一个UnitOfWork的工作实例,它使用它来实例化我的服务。所以,没有更多的无参数构造函数......
但这是RWTDI(正确的方法吗?)
答案 0 :(得分:2)
是的,这是配置绑定的正确方法。这是DI容器的重点,它根据构造函数的参数和您配置的内容计算出要注入的内容。
但是,我发现你的NinjectDependcyResolver很奇怪。你为什么不只是使用Ninject.MVC3? (它也适用于MVC4)。这将自动为MVC设置DependencyResolver,你可以在App_Start \ NinjectWebCommon.cs中配置你的映射
对于属性,正确的方法是使用随Ninject.MVC3自动安装的BindFilter扩展。您可以这样配置:
kernel.BindFilter<MyAuthorization>(FilterScope.Action, 0)
.WhenActionMethodHas<MyAuthorization>();
然后Ninject将自动处理注入其中的任何已配置对象。
这使得无需从属性内部调用GetService(这总是代码味道),并使所有内容协同工作。
至少,使用Ninject.MVC3设置你的MVC应用程序,然后在过滤器中,如果你真的想调用GetService,那么使用MVC DependencyResolver(Ninject.MVC自动注册)并执行类似这样的操作:
var x = DependencyResolver.Current.GetService<MyType>();
但是,你应该再使用BindFilter语法。