Ответ 1
Самый простой способ (IMO):
_className = (IClassName)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(IClassName));
Этот вопрос не связан конкретно с 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 при запуске приложения, из любого места в моем приложении, или есть ли лучший способ сделать это?
Привет,
Фред Шато
Самый простой способ (IMO):
_className = (IClassName)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(IClassName));
Более новая версия Ninject имеет этот метод, если используется с System.Web.MVC:
var obj = DependencyResolver.Current.GetService<IClassName>();
Если вам не нужно манипулировать привязками DI на лету, но создание стандартного ядра немного тяжело.
IKernel kernel = new StandardKernel();
var obj = DependencyResolver.Current.GetService<IClassName>();
Мне удалось заставить 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 было бы еще хуже.
Фред Шато
Похоже, вам нужно больше шаблона 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
}
}