首页 文章

全局访问Ninject内核

提问于
浏览
14

这个问题与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内核的新实例并不是一个好主意,因为这基本上是创建的第二个内核 .

那么,是否有可能从我的应用程序中的任何位置访问在Application Start中在Global.asax中实例化的现有内核,或者是否有更好的方法来完成此操作?

问候,

弗雷德城堡

4 回答

  • 4

    最简单的方法(IMO):

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

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

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

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

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

  • 1

    我设法使服务定位器工作,它似乎工作得很好 . 当请求通过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内核会更糟糕 .

    弗雷德城堡

  • 24

    听起来你需要更多Ninject的Factory模式实现 . 您可以将内核从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
        }
    }
    

相关问题