Условная привязка внедрения зависимостей только тогда, когда свойство не равно нулю
Это настольное приложение, которое обязано выдавать себя за текущего пользователя при доступе к базовому источнику данных.
Как я могу сказать Ninject не связывать зависимость, пока свойство родительского объекта не станет нулевым?
- Приложение вызывает аутентификацию пользователя при запуске
- После проверки подлинности ссылка на учетные данные текущего пользователя сохраняется в
IMembershipService
- При доступе к базовому источнику данных пользователь должен пройти аутентификацию, чтобы в строке конфигурации были указаны учетные данные для олицетворения
Я на самом деле использую NHibernate, и мне нужно динамически создать строку подключения на основе учетных данных пользователя, предоставленных при аутентификации.
Поэтому я хотел бы добиться:
public class DataModule : NinjectModule {
public override void Load() {
Bind<ISessionFactory>().ToProvider<SessionFactoryProvider>()
.When( // IMembershipService.CurrentUser != null );
}
}
Так как SessionProviderFactory
зависит от IMembershipService.CurrentUser
,
Я знаю, что это может быть не дизайн века, кроме того, мне нужно, чтобы он работал сейчас так, чтобы я мог доставить свой кусок потенциально отгружаемого продукта. Я буду рад рефакторинга потом.
SessionFactoryProvider
public class SessionFactoryProvider : Provider<ISessionFactory> {
public class SessionFactoryProvider(IMembershipService service) {
membershipService = service;
}
protected override ISessionFactory CreateInstance(IContext context) {
Configuration nhconfig = new Configuration().Configure();
nhconfig.AddAssembly(Assembly.GetExecutingAssembly());
nhconfig.Properties["connection.connection_string"] = buildConnectiongString();
return nhconfig.BuildSessionFactory();
}
private string buildConnectionString() {
return string.Format(membershipService.GetDefaultConnectionString()
, membershipService.CurrentUser.DatabaseInstanceName
, membershipService.CurrentUser.Login
, membershipService.CurrentUser.Password);
}
private readonly IMembershipService membershipService;
}
SessionProvider
public class SessionProvider : Provider<ISession> {
public class SessionProvider(ISessionFactory factory) {
sessionFactory = factory;
}
protected override ISession CreateInstance(IContext context) {
return sessionFactory.OpenSession();
}
private readonly ISessionFactory sessionFactory;
}
Дело в том, что я не могу создать экземпляр IMembershipService.CurrentUser
при запуске приложения. Пользователь должен сначала пройти аутентификацию в системе, следовательно, ActivationException
,
Ошибка активации ISession
Соответствующие привязки недоступны, и тип не является самосвязываемым.
Путь активации:
3) Внедрение зависимости ISession в сеанс параметров конструктора типа InquiriesRepository
2) Внедрение зависимости IInquiriesRepository в хранилище параметров конструктора типа InquiriesManagementPresenter
1) Запрос для запросов ManagementPresenter
Предложения:
1) Убедитесь, что вы определили привязку для ISession.
2) Если привязка была определена в модуле, убедитесь, что модуль был загружен в ядро.
3) Убедитесь, что вы случайно не создали более одного ядра.
4) Если вы используете аргументы конструктора, убедитесь, что имя параметра соответствует имени параметра конструкторов.
5) Если вы используете автоматическую загрузку модуля, убедитесь в правильности пути поиска и фильтров.
Итак, как я могу это сделать?
Любые предложения по улучшению дизайна приветствуются. Но имейте в виду, что мне нужно, чтобы он плохо работал. Я сделаю рефакторинг для следующей доставки.
РЕДАКТИРОВАТЬ
Похоже, я, возможно, мог бы использовать контекстно-зависимую инъекцию зависимости.
How to use the additional Ninject Scopes of NamedScope
И все же я не могу понять, как заставить это работать здесь в моем сценарии.
ОБНОВИТЬ
Из-за моих чтений я начинаю сомневаться, что, возможно, контекстное связывание будет более подходящим для моих нужд, чем условное связывание.
Какие-нибудь мысли?
В каждой статье, касающейся условного связывания, говорится об условном связывании типов, а не об условном связывании состояний.
В моем сценарии он определенно полагает, что это условное связывание состояний, отсюда и мысли о связывании контекста.
Тогда у меня будет две привязки.
- Прежде чем пользователь прошел аутентификацию
- После аутентификации пользователя
Так что, возможно, мне придется использовать ленивую инъекцию, которая решит мою проблему, в качестве примера ISessionFactory
не требуется при запуске приложения.
Я немного потерян здесь...
1 ответ
Вы могли бы создать условную привязку:
IBindingRoot.Bind<IFoo>().To<Foo>()
.When(request => request.ParentContext.Kernel.Get<IUserService>().AuthenticatedUser != null);
Но я не рекомендую это;-)
@Pacane
Условие Когда будет выполняться каждый раз, когда один запросит IFoo. Это переводит на другой запрос и, таким образом, несколько дорого.
Кроме того, этот подход работает только в случае, если есть родительский запрос. Если вы делаете IResolutionRoot.Get<IFoo>()
это бросит NullReferenceException
,
Вы можете обойти это, получив доступ к ядру, предоставленному синтаксисом. Но я не знаю, останется ли он там в будущих выпусках ninject...
Также лучше иметь механизм начальной загрузки приложения, который гарантирует, что вы создаете экземпляры только определенных частей дерева объектов после того, как "полностью инициализированы" (=> аутентифицированы). По крайней мере, по моему мнению.