【问题标题】:Accessing the Ninject Kernel Globally全局访问 Ninject 内核
【发布时间】:2013-03-11 12:05:26
【问题描述】:

这个问题与 Ninject 没有特别的关系。这更像是一个一般性的编码问题,但我将其发布在这里,以防万一在 Ninject 中可能有更好的方法来处理这个问题,而不是我正在尝试做的事情。

我想知道是否可以从 Global.asax 中的实例全局访问 Ninject 标准内核。

代码如下:

public class MvcApplication : NinjectHttpApplication
{
    protected override void OnApplicationStarted()
    {
        base.OnApplicationStarted();

        // MVC global registration, routing and filtering code goes here...
    }

    protected override IKernel CreateKernel()
    {
        return Container;
    }

    private static IKernel Container
    {
        get
        {
            IKernel kernel = new StandardKernel();
            kernel.Load(new ServiceModule(), new RepositoryModule());
            return kernel;
        }
    }
}

如果我有一些类,例如不与控制器接口的外观类,我想在其中开始依赖链,我的理解是我应该使用:

_className = kernel.Get<IClassName>();

但是,我知道的唯一方法是创建 Ninject 标准内核的新实例,但如果我理解正确的话,创建 Ninject 内核的新实例并不是一个好主意,因为那基本上是在创建第二个内核。

那么,是否可以从我的应用程序中的任何位置访问在应用程序启动时在 Global.asax 中实例化的现有内核,或者是否有更好的方法完全做到这一点?

问候,

弗雷德城堡

【问题讨论】:

    标签: asp.net-mvc ninject


    【解决方案1】:

    最简单的方法(IMO):

    _className = (IClassName)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(IClassName));
    

    【讨论】:

    • 感谢 Vasilij,这救了我的命!!!!我用它在非 MVC 类中设置数据注入。
    【解决方案2】:

    如果与 System.Web.MVC 一起使用,较新版本的 Ninject 具有此方法:

    var obj = DependencyResolver.Current.GetService<IClassName>();
    

    除非您需要动态操作 DI 绑定,但实例化 StandardKernel 有点繁重。

    IKernel kernel = new StandardKernel();
    var obj = DependencyResolver.Current.GetService<IClassName>();
    

    【讨论】:

    • 这是否有任何先决条件?我试过了,它只返回 null
    • 这个,DependencyResolver.Current.GetService&lt;IClassName&gt;() 在 Ninject v 3.20 和 Ninject.Web/MVC5 3.2.1 中为我工作得很好
    【解决方案3】:

    我设法让服务定位器工作,而且它似乎工作得很好。当请求通过 MVC 控制器操作方法进入应用程序时,Ninject 以 Ninject.Mvc.Extensions 提供的正常方式运行。它通过控制器构造函数注入实例类。当请求以任何其他方式进入应用程序时,我调用服务定位器以在该类构造函数中提供实例类。

    代码如下:

    首先,对 Microsoft.Practices.ServiceLocation 的引用

    还有下面的 Ninject 适配器类。

    public class NinjectServiceLocator : ServiceLocatorImplBase
    {
        public IKernel Kernel { get; private set; }
    
        public NinjectServiceLocator(IKernel kernel)
        {
            Kernel = kernel;
        }
    
        protected override object DoGetInstance(Type serviceType, string key)
        {
            return Kernel.Get(serviceType, key);
        }
    
        protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
        {
            return Kernel.GetAll(serviceType);
        }
    }
    

    在 Global.asax 中

    public class MvcApplication : NinjectHttpApplication
    {
        private static IKernel _kernel;
    
    
        protected override IKernel CreateKernel()
        {
            return Container;
        }
    
        private static IKernel Container
        {
            get
            {
                if (_kernel == null)
                {
                    _kernel = new StandardKernel();
                    _kernel.Load(new ServiceModule(), new RepositoryModule());
    
                    ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(_kernel));
                }
    
                return _kernel;
            }
        }
    }
    

    注意此代码需要使用 Ninject.Mvc.Extensions,它提供依赖解析器回退到默认控制器。否则,可能需要自定义依赖解析器。

    这似乎解决了我所有的顾虑。它创建实例类,解析整个对象图,并在我需要它工作的任何地方工作。而且,据我所知,每个应用程序只有一个 Ninject 标准内核。

    我知道使用服务定位器模式不受欢迎,但我想使用多个 Ninject 内核会不受欢迎,甚至更糟。

    弗雷德城堡

    【讨论】:

      【解决方案4】:

      听起来您需要更多的 Ninject 工厂模式实现。您可以将内核从 Global.asax 迁移到 Factory 类,该类可以与您的应用程序的其余部分进行交互。

      或者,如果您遇到在运行时指定的参数用于确定接口绑定的情况,您可以包装服务。这是 DI 和 ServiceLocater 的混合设置,但 ServiceLocater 仅发生在服务级别实例化,所有其他层通常以 DI/IOC 模式编码。

      MyService : IService1
      {
          public void DoSomething(MyCustomParameter parameter)
          {
              //Builds the Kernel using the supplied parameter
              //We've in our resolver bound IService1 To MyActualService
              var trueService = kernel.Get<IService1>();
              return trueService.DoSomething(parameter);
          }
      }
      
      MyActualService : IService1
      {
          public void DoSomething()
          {
              //Do the Actual work
          }
      }
      

      【讨论】:

      • 您是否知道设置工厂会如何影响 MVC 扩展的实现?
      • 遗憾的是,如果不尝试,我就不会知道那部分。由于独特的关注点和架构选择,我已将上面列出的包装方法用于我正在处理的应用程序。
      猜你喜欢
      • 2016-05-23
      • 2011-10-26
      • 2014-07-21
      • 2015-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-30
      相关资源
      最近更新 更多