When to use PerThreadLifetimeManager?

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).

Leave a Comment