I am adding dependency injection to my library and I use Unity for that. And I am wondering if I need to take some additional steps to make Unity Container thread-safe. I found couple of articles that are talking about Thread-safe container (example: http://www.fascinatedwithsoftware.com/blog/post/2012/01/04/A-Thread-Safe-Global-Unity-Container.aspx ) but I don't understand if I really need it in my project. From one side I don't want to have some nasty bugs due to race conditions from the other side I don't see in what case race condition would occur. I want to use Unity with Composition Root pattern and register all the types in the static constructor like that:
internal static class ConfiguredUnityContainer
{
private static readonly UnityContainer Container = new UnityContainer();
static ConfiguredUnityContainer()
{
Container.RegisterType<IConnectionFactory<SqlConnection>>();
}
public static T Resolve<T>()
{
return Container.Resolve<T>();
}
}
So, basically my question is: in what cases do I need additional thread-safe when I work with Unity DI? Where could I get race conditions or problems with thread-safety?
Unity (and all the common containers) are guaranteed (by their designers) to be thread-safe (or at least, sort of) in case of parallel resolves with no registrations. In other words, as long as you separate the registration phase from the resolve phase, and from one point on only resolve from the container, you can call
Resolve
in parallel from multiple threads without problems.As a matter of fact, as a best practice, you should always strictly separate the registration phase from the resolve phase, because this will lead to serious trouble and very hard to find race conditions.
This separation of those phases is so important, that some DI libraries (such as Autofac and Simple Injector) force this pattern upon you (where Simple Injector is the strictest of the two). The Simple Injector documentation contains a very clear explanation on why Simple Injector forces you upon this model and explains what could happen in case you would be able to change the configuration. To quote part of that explanation here (but you should definitely read the whole explanation):
As I see it, that the article you are linking goes more into the difference between the Service Locator anti-pattern and applying Dependency Injection correctly, which means only accessing the container inside your Composition Root. The writer of that article (Larry Spencer) isn't very clear, but inside his Composition Root, he creates one single Unity container and uses it for the duration of the whole application. In a sense it is still 'global', but he prevents that instance from being accessed through the application (because that is the Service Locator pattern).
Although the writer tries to create a thread-safe wrapper around the Unity container, his attempt is naive. What he does is creating a lock around every
Register
andResolve
method. Not only will this give enormous congestion in multi-threaded applications, it doesn't address the problems of what happens when registering and replacing instances after object graphs have already been build and cached, as both the Simple Injector documentation explains and this Unity question shows.In the case of dependency injection, thread safety considerations goes a level deeper than just the Container level. The type of dependency that you register into the Container also has great significance. In most cases, the dependencies that you are registering into the Container are singletons. If your container is static then it's global to all threads. In other words, every thread will have access to the same singleton instance. Therefore, if the dependency that you are registering maintains a state (stateful), then you need to consider that other threads may change that state. To avoid this kind of headache:
1) You could limit yourself to registering dependencies that are stateless.
2) You could make a [ThreadStatic] unity instance. In which case, each thread will have its own unity instance and stateful dependencies will be less of a problem.
3) The best option is to use Unity's PerThreadLifetimeManager for stateful dependencies. Which will guarantee that each thread will have its own instance of the dependency.