What pitfalls make UnityContainer thread safe?

I add dependency injection to my library, and for this I use Unity. And I'm wondering if I need to take extra steps to make Unity Container thread safe. I found a couple of articles that talk about a thread-protected container (for example: http://www.fascinatedwithsoftware.com/blog/post/2012/01/04/A-Thread-Safe-Global-Unity-Container.aspx ) but I don’t understand whether this is really necessary in my project. On the one hand, I do not want to have some unpleasant mistakes due to the conditions of the race, on the other hand, which I don’t see in which case the race condition will occur. I want to use Unity with the Root Composition pattern and register all types in a static constructor, like this:

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 safety when I work with Unity DI? Where can I get race conditions or thread safety issues?

+5
source share
2 answers

Unity (and all ordinary containers) are guaranteed (by their designers) to be thread-safe (or at least kind ) in case of parallel resolution without registration. In other words, as long as you separate the registration phase from the resolution phase and only allow from the container from one point, you can call Resolve in parallel from several threads without problems.

In fact, as a best practice, you should always strictly separate the registration phase from the decision phase, because it will lead to serious problems and it is very difficult to find the conditions of the race.

This separation of these phases is so important that some DI libraries (such as Autofac and Simple Injector ) impose this pattern on you (where Simple Injector is the strictest of the two). The Simple Injector documentation provides a very clear explanation of why Simple Injector makes you use this model and explains what could happen if you could change the configuration. To quote part of this explanation here (but you should definitely read the entire explanation):

Thread safety issues can easily occur when a user changes registrations during a web request. If the container allowed such registration changes during the request, other requests may be directly affected by these changes (since there is generally one instance of the container for the AppDomain). Depending on such things as lifestyle registration; the use of factories and how the schedule object is structured, it may be a real possibility that another request receives both old and new registrations. Take, for example, transition registration, which is replaced by another. If this is done when the graph of objects for another thread is resolved while the service is entered at several points within the graph, the graph will contain another instance of this abstraction with different lifetimes at the same time in the same request - and this is bad.

As I see it, the article you are linking more depends on the difference between Antivirus, Service Locator and the correct dependency injection, which means only access to the container inside the Composition Root . The writer of this article (Larry Spencer) is not very clear, but inside his composition root he creates one single Unity container and uses it throughout the application. In a sense, it is still “global,” but it denies access to this instance through the application (because it is a service locator pattern).

Although the author is trying to create a thread-safe wrapper around a Unity container, his attempt is naive. What it does is create a lock around each Register and Resolve method. Not only will this give enormous congestion in multi-threaded applications, it does not address the problem of what happens when registering and replacing instances after graphic objects have already been built and cached, as the Simple Injector documentation explains, and this is Unity.

+8
source

In the case of dependency injection, thread safety issues go deeper than just the container level. The type of dependency you register in the container is also of great importance. In most cases, the dependencies that you register on the Container are single. If your container is static, it is global across all threads. In other words, each thread will have access to the same singleton instance. Therefore, if the dependency that you register maintains a state (state), then you need to consider that other threads can change this state. To avoid this headache:

1) You can limit yourself to registering dependencies that have no status.

2) You can create an instance of unity [ThreadStatic]. In this case, each thread will have its own instance of unity, and state dependencies will be less of a problem.

3) The best option is to use the Unity PerThreadLifetimeManager for state dependencies. This ensures that each thread will have its own dependency instance.

+3
source

All Articles