Ninject: Как мне внедрить в библиотеку классов?

Для начала использую Ninject 1.5. У меня есть два проекта: веб-проект и библиотека классов. Моя конфигурация DI находится в веб-проекте. В моей библиотеке классов я определил следующее:

    public interface ICacheService<T>
    {
            string Identifier { get; }
            T Get();
            void Set( T objectToCache, TimeSpan timeSpan );
            bool Exists();
    }

А затем конкретный класс под названием CategoryCacheService.

В моем веб-проекте я связываю два:

Bind( typeof( ICacheService<List<Category>> ) ).To( typeof(CategoryCacheService)).Using<SingletonBehavior>();

В моей библиотеке классов есть методы расширения для класса HtmlHelper, например:

public static class Category
 {
  [Inject]
  public static ICacheService<List<Category>> Categories { get; set; }

  public static string RenderCategories(this HtmlHelper htmlHelper)
  {
   var c = Categories.Get();

   return string.Join(", ", c.Select(s => s.Name).ToArray());
  }
 }

Мне сказали, что вы не можете вводить в статические свойства, вместо этого я должен использовать Kernel.Get ‹> (). Однако ... Поскольку приведенный выше код находится в библиотеке классов, у меня нет доступ к ядру. Как я могу получить ядро ​​с этого момента или есть лучший способ сделать это?


person Denny Ferrassoli    schedule 30.10.2009    source источник


Ответы (2)


Хороший вопрос.

Половина идеи использования DI состоит в том, чтобы убрать озабоченность / тонкую настройку поведения экземпляра из кода при внедрении. Следовательно, может иметь смысл изменить класс Category, чтобы он больше не был static, объявить его зависимости в ctor и позволить клиентскому коду сшить его вместе.

Относительно того, как получить к нему доступ, если вы действительно уверены, что это хорошая идея ... Как правило, в вашем случае идея состоит в том, чтобы создать CacheServiceResolver и зарегистрировать его [в вашем веб-проекте]. Затем передайте ему экземпляр Kernel в качестве создаваемого. Таким образом, ваша DLL будет привязана только к интерфейсу вашего CacheServiceResolver.

Другой часто используемый подход состоит в том, чтобы иметь последнее средство «Service Locator» где-нибудь в глобальном масштабе, которое предоставляет «GlobalGet». Но это вообще плохая идея, и ее следует использовать только для временной проклейки воздуховодов.

Еще одна вещь, на которую стоит обратить внимание, - это Common Service Locator, который позволит сделать библиотеку нейтральной в отношении контейнеров, хотя за пределами EL вы не найдете много использования как вам не следует показывать свой контейнер.

Другой вариант - запросить Func<T> фабричный метод и Bind его лямбда-выражение, которое его разрешает, извлекая этот поиск из вашего кода.

РЕДАКТИРОВАТЬ: В Ninject 2 нет необходимости явно передавать Kernel экземпляров, как я уже сказал - можно просто запросить IKernel в вашем ctor, и вы его получите, независимо от того, передает ли запрос разрешения явно.

РЕДАКТИРОВАТЬ 2: Очень недоволен своим ответом, попытался сделать его более общим, не слишком его убивая. Подводя итог, можно сказать, что желательные варианты обычно расположены в следующем порядке:

  1. без артефактов контейнера, оставьте прошивку клиенту
  2. предоставить нейтральную для контейнера точку расширения, специально предназначенную для выполнения чего-либо в контексте вашей библиотеки, используя терминологию на универсальном языке домена вашей библиотеки вместо нейтрализованных абстрактных терминов контейнера
  3. обеспечить нейтральный контейнерный подход к интеграции а-ля Common Service Locator
  4. only then consider having people needing to
    • know your container
    • понять ваш контейнер
person Ruben Bartelink    schedule 31.10.2009
comment
Рубен, CacheServiceResolver кажется мне правильной идеей, поскольку я могу повторно использовать этот шаблон в будущем. У вас есть примеры настройки резольвера? - person Denny Ferrassoli; 02.11.2009
comment
К сожалению, у меня нет ни одного под рукой. Общая идея заключается в том, что где бы вы ни создавали свой новый StandardKernel, вы храните ссылку на него. Тогда у вас есть такая простая вещь, как void RegisterCacheServiceResolver(Kernel kernel) {Bind<ICacheServiceResolver>().ToConstant( new CacheServiceResolver( kernel));} на одном из модулей, которому вы передаете ядро. Или вы можете создать ядро, а затем передать его конструктору любого модуля, который в нем нуждается, после чего вы добавляете модуль [вместо того, чтобы передавать их все в конструктор ядра, как это обычно делается]. - person Ruben Bartelink; 02.11.2009

В веб-проекте выполните следующую команду из консоли диспетчера пакетов.

Install-Package Ninject.MVC3

У вас должен получиться модуль NinjectWebCommon в папке App_Start.

Внизу вы можете добавить свои зависимости, как показано ниже:

private static void RegisterServices(IKernel kernel)
{   
 kernel.Bind<IPeopleRepository>().To<PeopleRepository>();
}

В проекте библиотеки классов выполните следующую команду:

Install-Package Ninject

Вот как внедрить сервис с репозиторием из библиотеки классов:

public class PeopleService : IPeopleService
{
 private readonly IPeopleRepository _peopleRepository;

 [Inject]
 public PeopleService(IPeopleRepository peopleRepository)
 {
    this._peopleRepository = peopleRepository;
 }
}
person hutchonoid    schedule 24.04.2013