Как настроить Ninject, чтобы он вставлял правильный экземпляр в зависимости от ранее внедренного экземпляра - PullRequest
3 голосов
/ 16 июня 2011

Я не могу найти правильные слова для своего вопроса, поэтому вместо этого я позволю своему коду говорить.

У меня есть репозиторий:

class Repository
{
    public Repository(DbContext ctx)
    {

    }
}

тогда у меня есть эти привязки:

Bind<IRepository>().To<Repository>();
Bind<DbContext>().To<UserStoreContext>().When...
Bind<DbContext>().To<CentralStoreContext>().When...

и тогда у меня есть класс, который должен получить доступ к обоим БД

class Foo
{
    public Repository(IRepository userRepo, [CentralStoreAttribute]IRepository centralRepo)
    {

    }
}

Как мне настроить две привязки DbContext, чтобы репозитории с правильным контекстом (на основе CentralStoreAttribute) были вставлены в конструктор Foo?

Ответы [ 4 ]

1 голос
/ 16 июня 2011

Используйте перегрузку When(Func<IRequest, bool> condition), чтобы рекурсивно проверить, истинно ли r.Target.IsDefined(typeof(TAttribute), false) для данного запроса или одного из его предков r.ParentRequest

1 голос
/ 16 июня 2011

Я попробовал это в качестве доказательства концепции, но в итоге пошел в другом направлении.

Bind<IRepository>().ToMethod(x =>
{
  var repositoryType = x.Kernel
                .Get<IConfigObject>()
                .SomeStringPropertyDenotingTheRepository;

  switch (repositoryType )
  {
    case "1": return (IRepository)new Repository1();
    default: return (IRepository)new Repository2();
  }
}).InRequestScope();

Хотя это работало, я так и не понял, использует ли он мой одноэлементный экземпляр IObjectB или создает новый экземпляр - хотя это должно быть довольно легко выяснить. Я подумал, что он вызывает ToMethod каждый раз, когда я использовал DI в IRepository - опять не проверено.

0 голосов
/ 16 июня 2011

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

Так что, если вам нужно «запросить» хранилище пользователя по сравнению с центральным, я бы создал типы с псевдонимом, подобным этому:

interface IRepository {  /* methods and properties */ }
interface IUserRepository : IRepository {}
interface ICentralRepository : IRepository {}

class Foo
{
   public Foo(IUserRepository userRepo, ICentralRepository centralRepo)
   {
      // assign to fields
   }
}

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

0 голосов
/ 16 июня 2011
Bind<IRepository>().To<Repository>();
Bind<DbContext>().To<CentralStoreContext>()
    .When( context => context.Target != null 
        && context.Target.GetCustomAttributes( typeof( CentralStoreAttribute ) ) != null );

// make the general binding after the more specific one
Bind<DbContext>().To<UserStoreContext>();
...