0

[注意:我的 NinjectDependencyResolver 类位于此问题的底部。]

设置:

在 ASP.NET MVC 4 应用程序中,我有使用服务的控制器。

每个服务都有一个 IUnitOfWork 接口作为构造函数参数。例如:

public ClientService(IUnitOfWork uow){ //... }

在 Global.asax.cs 类中注册一个适当编写NinjectDependencyResolver : IDependencyResolver的类允许这些服务正确实例化并且一切正常。到目前为止,一切都很好。

但是,在某些情况下,服务需要在其他一些代码中实例化,例如,在属性中。例如:

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 实例。

这个我不知道该怎么做,所以这是我的第二个问题:

问题2:

如何菊花链 IUnitOfWork 构造参数的依赖注入以正确实例化 ClientService?(请参阅下面我注释掉的努力 - 我将其注释掉是因为它对我来说甚至没有意义 - 我不应该创建 UnitOfWork 的新实例,不是吗?):

NinjectDependencyResolver 类:

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(正确的方法)吗?

4

1 回答 1

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 语法。

于 2012-10-16T20:13:40.730 回答