【问题标题】:Conditional dependency injection binding only when property not null仅当属性不为空时才进行条件依赖注入绑定
【发布时间】:2014-04-01 17:41:53
【问题描述】:

它是一个桌面应用程序,在访问底层数据源时必须模拟当前用户。

如何告诉 Ninject 在父对象的属性不为空之前不要绑定依赖项?

  1. 应用程序在启动时强制进行用户身份验证
  2. 一旦通过身份验证,对当前用户凭据的引用将保存在IMembershipService
  3. 访问底层数据源需要对用户进行身份验证,以便commection 字符串说明要模拟的凭据

我实际使用的是 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;
}

会话提供者

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类型的构造函数的参数session中

2) 将依赖 IInquiriesRepository 注入到 InquiriesManagementPresenter 类型的构造函数的参数存储库中

1) 请求 InquiriesManagementPresenter

建议:

1) 确保您已为 ISession 定义绑定。

2) 如果绑定是在模块中定义的,请确保该模块已加载到内核中。

3) 确保您没有意外创建多个内核。

4) 如果您使用构造函数参数,请确保参数名称与构造函数参数名称匹配。

5) 如果您使用自动模块加载,请确保搜索路径和过滤器正确。

那么,我该怎么做呢?

欢迎提出任何设计改进建议。但请记住,我需要它才能很好地工作。我会为下一次交付重构。

编辑

看起来我也许可以使用上下文/范围依赖注入。

How to use the additional Ninject Scopes of NamedScope

而且,我仍然无法弄清楚如何让它在我的场景中工作。

更新

通过阅读,我开始怀疑上下文绑定是否比条件绑定更适合我的需求。

有什么想法吗?

每篇与条件绑定相关的文章都在讨论条件类型绑定,而不是条件状态绑定。

在我的场景中,它特别认为它是一个条件状态绑定,因此有关于上下文绑定的想法。

然后,我会有两个绑定。

  1. 用户通过身份验证之前
  2. 用户通过身份验证后

所以也许我要么必须使用延迟注入,这可以解决我的问题,因为在应用程序启动时不需要 ISessionFactory 的实例。

我有点迷茫了……

【问题讨论】:

  • 仅当运行它所需的一切都可用时才使用Lazy&lt;ISession&gt; 注入或创建实例。另一种方法是代理ISession 并在底层实现可用时交换它。如果在会话可用之前调用代理,则抛出异常。但我认为我宁愿只在所需的一切可用时构建对象树的受影响路径。

标签: c# nhibernate dependency-injection ninject conditional-binding


【解决方案1】:

您也许可以创建条件绑定:

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

但我不推荐它;-)

@Pacane

When 条件将在每次请求 IFoo 时执行。它转换为另一个请求,因此有点昂贵。

此外,这种方法仅适用于有父请求的情况。如果您执行IResolutionRoot.Get&lt;IFoo&gt;(),它将抛出NullReferenceException

您可以通过访问语法提供的内核来解决这个问题。但我不知道它是否会在 ninject 的未来版本中保留...


此外,拥有一个应用程序引导机制来确保您仅在“完全初始化”(=> 身份验证)之后才实例化对象树的某些部分是一个更好的设计。至少在我看来。

【讨论】:

  • +1 提供实现它的方法,但不推荐。这在开始使用 DI 时非常有用,因此可以在此过程中不断改进。
  • @BatteryBackupUnit 为什么不推荐它?
  • @Pacane 我已将我对此事的看法添加到答案中。
  • 所以,据我了解,您不会为此使用 Ninject,而是会在引导机制中手动执行?
  • 是的,基本上,不要“条件”绑定,不要把责任放在 IoC 上,而只是确保你以正确的顺序做事。无论如何,这是业务需求。
猜你喜欢
  • 2022-01-25
  • 2014-09-20
  • 2019-04-04
  • 2012-03-10
  • 2016-08-29
  • 1970-01-01
  • 2020-10-24
  • 2022-06-29
  • 2013-03-30
相关资源
最近更新 更多