When to use PerThreadLifetimeManager?
G

1

12

I am following the example linked to below for setting up unity to work with my service layer. My project is setup very similar to the one in this article and I understand everything except why exactly is PerThreadLifetimeManager used when registering the service dependency. Keep in mind I am also using a generic repository and unit of work that is being used in my service layer as well. Most unity examples use the default (transient) lifetime manager, and since my setup is similar to the one below I'm wondering why I should use the PerThreadLifeimeManager? I am using an ASP.NET web forms project for my current presentation layer if that changes anything.

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

[The repository pattern with EF code first dependency injection in asp.net MVC 3][1] [1]: http://www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef-code-first-dependeny-injection-in-asp-net-mvc3.html

Gelatinous answered 29/1, 2013 at 20:14 Comment(0)
B
32

The Per Thread Lifetime is a very dangerous lifestyle and in general you should not use it in your application, especially web applications.

This lifestyle should be considered dangerous, because it is very hard to predict what the actual lifespan of a thread is. When you create and start a thread using new Thread().Start(), you'll get a fresh block of thread-static memory, which means the container will create a new per-threaded instance for you. When starting threads from the thread pool using ThreadPool.QueueUserWorkItem however, you get possibly an existing thread from the pool. The same holds when running in ASP.NET. ASP.NET pools threads to increase performance.

This means that a thread will almost always outlive a web request. ASP.NET on the other hand can run requests asynchronously, which means that a web request can be finished at a different thread. And this is a problem when working with a Per Thread lifestyle. And of course this effect is amplified when you start using async/await.

This is a problem since you will typically call Resolve<T> once at the beginning of the request. This will load the complete object graph including your services that are registered with the Per Thread lifestyle. When ASP.NET finishes the request at a different thread, this means that the resolved object graph moves to this new thread, including all Per Thread registered instances.

Since these instances are registered as Per Thread, they are probably not suited to be used at another thread. They are almost certainly not thread-safe (otherwise they would be registered as Singleton). Since the first thread that initially started the request is already free to pick up new requests, you can run into the situation where two threads access those Per Thread instances simultaneously. This will lead to race conditions and bugs that are hard to diagnose and find.

So in general, using Per Thread is a bad idea. Instead use a lifestyle that has a clear scope (an implicit or explicitly defined begin and end). The Per Web Request lifestyle that most DI frameworks implement is often implicitly scoped (you don't have to end it yourself).

Specific to your question

To make things worse, the blog post you referenced contains a configuration error. The ICatalogService is defined with a Per Thread lifestyle. This service however depends on an IDALContext service, which is defined as Transient. Since a reference to a IDALContext instance is stored as private field inside the CatalogService, this means the DALContext lives as long as the ICatalogService does. This is a problem because IDALContext is defined as Transient and is probably not thread-safe.

The General Rule Of Lifestyle

The general rule is to let components only depend on services with an equal or longer lifetime. So a Transient can depend on a Singleton but not the other way around.

Since a Per Thread registered component will typically live very long, it can typically only safely depend on other Per Thread or Singleton instances. And since ASP.NET can split a single request up in multiple threads, it is not safe to use Per Thread in the context of a ASP.NET application (both MVC, Web Forms, and especially Web API).

Bainbrudge answered 29/1, 2013 at 21:14 Comment(3)
I used Per-thread in my web services and it caused all kinds of havoc. It caused exception that only occurred when traffic increased...very hard to reproduce.Importune
@Steven, it has been a long time since this post, but I have a legacy project that services are registered as Singleton lifestyle, and the DbContext is registered as PerThread just only if HttpContext is null, this is for Hangfire background jobs, and PerRequset for normal web requests. S when traffic increases, we get lots of deadlocks and I am sure that it is because of the PerThread lifestyle of DbContext. We are using Unity v5, what can you offer for dbContext's lifestyle for hangfire jobs?Novelty
Hi @ibubi, I'm not that familiar with Unity, but I think in Unity its scoping mechanism is achieved through child containers. That would mean that your Hangfire infrastructure should create a new child container for each executed job; from that child container you resolve and execute the root service; and finally you dispose the child container at the end of the job.Bainbrudge

© 2022 - 2024 — McMap. All rights reserved.