Подтвердить что ты не робот

Доступ к ядру Ninject во всем мире

Этот вопрос не связан конкретно с Ninject. Это скорее общий вопрос кодирования, но я отправляю его здесь, если может быть лучший способ справиться с проблемой в Ninject, чем то, что я пытаюсь сделать.

Я хотел бы знать, можно ли получить доступ к ядру Ninject Standard Kernel глобально, из его экземпляра в Global.asax.

Вот код:

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 Standard, но если я правильно понимаю, не рекомендуется создавать новый экземпляр ядра Ninject, потому что это в основном создает второе ядро.

Итак, возможно ли получить доступ к существующему ядру, которое было создано в Global.asax при запуске приложения, из любого места в моем приложении, или есть ли лучший способ сделать это?

Привет,

Фред Шато

4b9b3361

Ответ 1

Самый простой способ (IMO):

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

Ответ 2

Более новая версия Ninject имеет этот метод, если используется с System.Web.MVC:

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

Если вам не нужно манипулировать привязками DI на лету, но создание стандартного ядра немного тяжело.

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

Ответ 3

Мне удалось заставить Service Locator работать, и, похоже, он работает очень хорошо. Когда запрос поступает в приложение через метод действия контроллера MVC, функции Ninject выполняются обычным способом, предоставляемым Ninject.Mvc.Extensions. Он вводит классы экземпляра через конструктор контроллера. Когда запрос поступает в приложение любым другим способом, я вызываю Service Locator для предоставления классов экземпляра в этом конструкторе классов.

Здесь код:

Во-первых, ссылка на 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 Standard Kernel.

Я знаю, что использование шаблона Service Locator неодобрительно, но я полагаю, что использование более чем одного ядра Ninject было бы еще хуже.

Фред Шато

Ответ 4

Похоже, вам нужно больше шаблона Factory для 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
    }
}