为什么PerThreadLifetimeManager在此示例中使用?

use*_*121 11 dependency-injection unity-container unit-of-work object-lifetime repository-pattern

我按照下面链接的示例来设置统一以使用我的服务层.我的项目设置与本文中的项目非常相似,我理解除了为什么在注册服务依赖项时使用PerThreadLifetimeManager的所有内容.请记住,我也在使用我的服务层中使用的通用存储库和单元工作.大多数统一示例使用默认(瞬态)生命周期管理器,因为我的设置类似于下面的设置,我想知道为什么我应该使用PerThreadLifeimeManager?我正在为我当前的表示层使用ASP.NET Web表单项目,如果它发生了任何变化.

container.RegisterType<ICatalogService, CatalogService>(new PerThreadLifetimeManager())
Run Code Online (Sandbox Code Playgroud)

在asp.net MVC 3中使用EF代码第一个依赖注入的存储库模式

Ste*_*ven 30

Per Thread Lifestyle被认为是有害的

每线程寿命是一个非常危险的生活方式,一般你应该不是在你的应用程序,特别是Web应用程序中使用.

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

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

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

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

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

具体到您的问题

更糟糕的是,您引用的博客文章包含配置错误.在ICatalogService与定义每个线程的生活方式.但是,此服务依赖于IDALContext服务,该服务定义为Transient.由于对IDALContext实例的引用被存储为私有字段CatalogService,因此这意味着DALContext生命与其一样长ICatalogService.这是一个问题,因为它IDALContext被定义为Transient并且可能不是线程安全的.

生活方式的一般规则

一般规则是让组件仅依赖具有相同或更长寿命的服务.因此,瞬态可以依赖于单身人士而不是相反.

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

  • 我在我的网络服务中使用了Per-thread,它造成了各种各样的破坏.它引起了异常,只有在交通量增加时才会发生......非常难以重现. (2认同)