为什么在这个例子中使用PerThreadLifetimeManager?

我正在关注下面的例子来设置统一与我的服务层一起工作。 我的项目设置与本文中的非常相似,除了为什么在注册服务依赖项时使用PerThreadLifetimeManager,我明白了一切。 请记住,我也在使用我的服务层中使用的通用存储库和unitofwork。 大多数统一的例子使用默认(瞬态)生存期pipe理器,因为我的设置类似于下面的我想知道为什么我应该使用PerThreadLifeimeManager? 如果改变了任何东西,我正在为当前表示层使用ASP.NET Web窗体项目。

container.RegisterType<ICatalogService, CatalogService>(new PerThreadLifetimeManager()) 

在asp.net MVC 3中使用EF代码第一个dependency injection的存储库模式

每线程生活方式被认为是有害的

每个线程的生命周期是一个非常危险的生活方式,一般来说你不应该在你的应用程序中使用它,特别是Web应用程序。

这种生活方式应该被认为是危险的,因为很难预测线程的实际使用寿命。 当你使用new Thread().Start()创build并启动一个线程时,你会得到一个全新的线程静态内存块,这意味着容器将为你创build一个新的线程实例。 当使用ThreadPool.QueueUserWorkItem从线程池启动线程时,您可能会从该池中获得一个现有的线程。 在ASP.NET中运行时也是如此。 ASP.NET将线程池化以提高性能。

这意味着一个线程将几乎总是比一个Web请求长。 另一方面,ASP.NET可以asynchronous地运行请求,这意味着Web请求可以在不同的线程完成。 使用Per Thread生活方式时,这是个问题。 当然,当你开始使用async / await时,这个效果会被放大。

这是一个问题,因为在请求开始时通常会调用Resolve<T>一次。 这将加载完整的对象图,包括您使用Per Thread生活方式注册的服务。 当ASP.NET在不同的线程完成请求时,这意味着parsing的对象图移动到这个新线程,包括所有Per线注册的实例。

由于这些实例被注册为Per Thread,它们可能不适合在另一个线程中使用。 它们几乎肯定不是线程安全的(否则它们将被注册为Singleton)。 由于最初启动请求的第一个线程已经可以自由地接收新请求,我们可以运行两个线程同时访问这些Per Thread实例的情况。 这将导致竞争条件和难以诊断和发现的错误。

所以一般来说,使用Per Thread是一个坏主意。 取而代之的是使用具有明确范围的生活方式(隐式或明确定义的开始和结束)。 大多数DI框架实现的Per Web Request生活方式通常是隐式的(您不必自己结束)。

具体到你的问题

更糟糕的是,您引用的博客post包含configuration错误。 ICatalogServicePer Thread生活方式定义。 然而这个服务依赖于一个IDALContext服务,它定义为Transient 。 由于对IDALContext实例的引用作为私有字段存储在CatalogService ,这意味着只要ICatalogService存在。 这是一个问题,因为IDALContext被定义为Transient ,并且可能不是线程安全的。

生活方式的一般规则

一般规则是让组件只依赖于具有相等或更长的生命周期的服务。 所以一个瞬变可以依靠一个单身而不是相反。

由于每个线程注册的组件通常会活得很长,因此通常只能安全地依赖其他每个线程或单个实例。 由于ASP.NET可以在多个线程中分割单个请求,因此在ASP.NET应用程序(包括MVC,Web Forms,尤其是Web API)的上下文中使用Per Thread并不安全。