Как настроить Ninject так, чтобы он вставлял правильный экземпляр в зависимости от ранее внедренного экземпляра
Я не могу найти правильные слова для моего вопроса, поэтому я позволю своему коду говорить вместо этого.
У меня есть репозиторий:
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 ответа
Вместо того, чтобы полагаться на атрибуты в нужных местах, я обычно создаю несколько типов, которые фактически являются просто псевдонимами. Это полезно, поскольку в 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 вообще не попадает в мое приложение, оно более декларативно, и я думаю, что его проще запомнить, чем любой подход, основанный на соглашениях, такой как тот, который вы пробуете.
Использовать When(Func<IRequest, bool> condition)
перегрузка, чтобы проверить рекурсивно, если r.Target.IsDefined(typeof(TAttribute), false)
верно для данного запроса или для одного из его предков r.ParentRequest
Я попробовал это в доказательство концепции, но в конечном итоге пошел в другом направлении.
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 - опять не проверено.
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>();