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

Это настольное приложение, которое обязано выдавать себя за текущего пользователя при доступе к базовому источнику данных.

Как я могу сказать Ninject не связывать зависимость, пока свойство родительского объекта не станет нулевым?

  1. Приложение вызывает аутентификацию пользователя при запуске
  2. После проверки подлинности ссылка на учетные данные текущего пользователя сохраняется в IMembershipService
  3. При доступе к базовому источнику данных пользователь должен пройти аутентификацию, чтобы в строке конфигурации были указаны учетные данные для олицетворения

Я на самом деле использую 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

И все же я не могу понять, как заставить это работать здесь в моем сценарии.

ОБНОВИТЬ

Из-за моих чтений я начинаю сомневаться, что, возможно, контекстное связывание будет более подходящим для моих нужд, чем условное связывание.

Какие-нибудь мысли?

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

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

Тогда у меня будет две привязки.

  1. Прежде чем пользователь прошел аутентификацию
  2. После аутентификации пользователя

Так что, возможно, мне придется использовать ленивую инъекцию, которая решит мою проблему, в качестве примера ISessionFactory не требуется при запуске приложения.

Я немного потерян здесь...

1 ответ

Решение

Вы могли бы создать условную привязку:

IBindingRoot.Bind<IFoo>().To<Foo>()
    .When(request => request.ParentContext.Kernel.Get<IUserService>().AuthenticatedUser != null);

Но я не рекомендую это;-)

@Pacane

Условие Когда будет выполняться каждый раз, когда один запросит IFoo. Это переводит на другой запрос и, таким образом, несколько дорого.

Кроме того, этот подход работает только в случае, если есть родительский запрос. Если вы делаете IResolutionRoot.Get<IFoo>() это бросит NullReferenceException,

Вы можете обойти это, получив доступ к ядру, предоставленному синтаксисом. Но я не знаю, останется ли он там в будущих выпусках ninject...


Также лучше иметь механизм начальной загрузки приложения, который гарантирует, что вы создаете экземпляры только определенных частей дерева объектов после того, как "полностью инициализированы" (=> аутентифицированы). По крайней мере, по моему мнению.

Другие вопросы по тегам