我正在使用简单的注射器3.0.4
我有一项服务,其生活方式的范围取决于具有短暂生活方式的服务。
当我调用container.Verify()时,出现有关生活方式不匹配的诊断错误。
导致问题的临时服务已注入到其他临时服务中,因此在继续进行整个项目范围之前,我需要询问一下。为什么从任何生活方式的范围到短暂性的依赖都是一个问题?每次注入瞬态时,都会对它们进行新的更新,因此不会有其他干扰。本质上,瞬态对象的生存期由注入的服务决定。
另外,我已经从这里阅读了有关此主题的文档,并且我确实理解了为什么您不希望单例依赖于范围服务,但是肯定依赖于瞬态始终是安全的吗?
每次注入瞬态时,都会对它们进行新的更新,因此不会有其他干扰。
每次您从容器中请求瞬态时,都会对其进行更新,但是一旦将瞬态注入到组件中,它们将在该组件存在的整个过程中一直存在。因此,如果使用组件是单例,这意味着它将拖动所有依赖项,实际上也使它们成为单例。当您查看通常如何实现依赖项注入时,此行为将变得显而易见:
public class SomeComponent
{
private readonly ILogger logger;
private readonly IService service;
public SomeComponent(ILogger logger, IService service) {
this.logger = logger;
this.service = service;
}
}
如您所见,依赖项存储在组件的私有字段中,这将使它们在生命周期内一直存在,SomeComponent
并且SomeComponent
将继续使用相同的依赖项。
本质上,瞬态对象的生存期由注入的服务来控制。
究竟; 一个组件的生活方式至少与它的消费者一样长。但是,一个依赖项可能有多个具有不同生活方式的消费者,这使得很难看到该依赖项的寿命。当注入到使用者1中时,它可能在请求的持续时间内有效,而注入到使用者2中的该依赖项的另一个实例将与应用程序一样有效。
就像作用域实例一样,临时注册通常也不是线程安全的。否则,您将把它们注册为单例。保持瞬态生存更长的时间显然会导致并发错误或与陈旧数据相关的错误。这就是为什么Simple Injector默认情况下不允许这样做并引发异常的原因。
与Simple Injector相比,您可能会对Autofac如何定义其生活方式感到困惑。Autofac不包含瞬态生活方式。相反,它有一种InstancePerDependency
生活方式。从技术上讲,这与瞬态相同,但意图却大不相同。随InstancePerDependency
您说:“无论生活方式如何,该组件的寿命都应与其消费者一样长”。在某些情况下,这是有道理的,但是通过这样做,您实际上忽略了房间里的大象,而且我发现缺乏检测是常见的错误来源。在大多数情况下,如果您不关心组件的生活方式,则意味着应将其注册为单例-而不是InstancePerDependency
。
Simple Injector不允许将瞬态注入到有作用域的实例中的原因是,有作用域的实例也可以生存很长时间(取决于应用程序),并且您不能总是假定瞬态可以安全地注入到有作用域的使用者中。
最后,所有这些都是关于传达代码意图的。如果组件是无状态的或线程安全的,则应将其注册为单例。它不是线程安全的,您可以将其注册为作用域或临时的。这使任何阅读配置的人都清楚知道他应该如何处理此类组件,并且它使Simple Injector可以为您检测任何配置错误。
当Simple Injector为您检测到错误配置时,我得出的结论是,当您的系统是围绕纯粹由单例组件组成的对象图进行设计时,可以大大简化您的DI配置。我在这里表达了这些想法。这将消除我们在进行依赖注入时所面临的许多复杂性,甚至比DI本身已经更快地公开了违反SOLID原则的情况。
在继续进行整个项目之前
我不建议这样做。通常,您会看到应用程序中只有某些“叶子组件”是有作用域的(例如DbContext
)。这些范围内的组件不依赖于许多其他组件。您编写的组件通常应该是无状态的,不需要任何缓存。因此,在使对象图单例成为(但不是)选项的情况下,我通常会使尽可能多的对象图成为瞬态对象,并且只有少数几个叶组件处于范围内。由于瞬态可以安全地依赖于作用域实例,因此一切都会按预期进行。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句