验证强制延迟服务初始化

时间:2018-08-03 13:36:02

标签: c# dependency-injection simple-injector

首先,谢谢您-我被Simple Injector强迫成为了一个更好的程序员。

很早在程序引导时,我就设置了根容器,并随后不久调用container.Verify()

我的许多服务都依赖于(我的类)ICurrentUser,该类具有检索帐户密码和配置的方法。可以预料,这些机密只有在用户通过身份验证后才可用,而在引导和调用container.Verify()期间并没有发生。

示例:

private readonly string serviceAccount;

public SomeService(ICurrentUser currentUser) {
    serviceAccount = currentUser.GetSecret("SomeServiceAccount");
}

这使我将以上内容更改为:

private Lazy<string> serviceAccount;

public SomeService(ICurrentUser currentUser) {
    serviceAccount = 
        new Lazy<string>(() => currentUser.GetSecret("SomeServiceAccount"));
}

,然后在需要时引用serviceAccount.Value。 这似乎有点尴尬,并使ctor复杂化。或者,我可以将验证推迟到用户进行身份验证之后,但我真的不喜欢这样做,因为它可以推迟设置ctor之后应该发生的情况。

我是否可以将验证过程拆分为服务关系的初始轻量级验证,但不执行构造函数,直到后续步骤?

1 个答案:

答案 0 :(得分:1)

构造器应该没有任何逻辑,除了进行前提条件检查和存储传入的依赖关系外,正如Mark Seemann的here所述。这意味着您不应从构造函数内部对注入的依赖项进行任何调用,因为:

  • 这种调用可能会失败,从而导致对象图的构建变得不可靠
  • 在创建组件期间,此时注入的依赖关系图可能尚未完全初始化,这使构造函数很脆弱。
  • 依赖关系的调用可能导致构造函数依赖于运行时数据(例如您的用户的机密)的可用性或外部资源(例如一个数据库)的可用性,这使得验证容器的配置变得更加困难,这就是您已经体验过的东西。但是,如我所解释的here,组件的构造函数不应依赖于运行时数据的可用性。

解决此问题的方法很简单,就是将传入的ICurrentUser依赖项存储在SomeService类中,并且仅在GetSecret的方法之一中调用其SomeService方法被调用。

您可能很想让值的加载变得懒惰,尤其是防止必须一遍又一遍地加载它,如果在GetSecret的整个生命周期中多次调用SomeService时可能会发生这种情况。

但是,您应该避免在该级别上实现缓存,因为这会使SomeServiceICurrentUser的所有其他使用者变得复杂。取而代之的是,您应该在ICurrentUser实现内部实现缓存 ,或者-将实现包装在添加了缓存行为的Decorator中。在Simple Injector中注册装饰器是trivial