Autofac is designed for use in highly-concurrent applications. The guidance below will help you be successful in these situations.
ComponentRegistryBuilder are not thread-safe and are designed to be used only on a single thread at the time the application starts up. This is the most common scenario and works for almost all applications.
All container operations are safe for use between multiple threads.
To reduce locking overhead, each
Resolve operation takes place in a ‘context’ that provides the dependency-resolution features of the container. This is the parameter provided to component registration delegates.
Resolution context objects are single-threaded and should not be used except during the course of a dependency resolution operation.
Avoid component registrations that store the context:
// THIS IS BROKEN - DON'T DO IT
builder.Register(c => new MyComponent(c));
In the above example, the “c”
IComponentContext parameter is being provided to MyComponent (which takes
IComponent as a dependency). This code is incorrect because the temporary “c” parameter will be reused.
IComponentContext from “c” to access the non-temporary context:
IContext threadSpecificContext = c.Resolve<IComponentContext>(); // access real context.
return new MyComponent(threadSpecificContext);
Take care also not to initialize components with closures over the “c” parameter, as any reuse of “c” will cause issues.
The container hierarchy mechanism further reduces locking, by maintaining local copies of the component registrations for any factory/container components. Once the initial registration copy has been made, a thread using an ‘inner’ container can create or access such components without blocking any other thread.
When making use of the LifetimeEvents available, don’t call back into the container in handlers for the
Activated events: use the supplied
Thread Scoped Services
You can use Autofac to register services that are specific to a thread. The instance lifetime scope page has more information on this.
Keeping in mind the guidelines above, here’s a little more specific information about thread safety and locking in Autofac.
The following types are safe for concurrent access by multiple threads:
Disposer(default implementation of
LifetimeScope(default implementation of
These types cover practically all of the runtime/resolution scenarios.
The following types are designed for single-threaded access at configuration time:
ComponentRegistryBuilder(default implementation of
So, a correct Autofac application will use a
ContainerBuilder on a single thread to create the container at startup. Subsequent use of the container can occur on any thread.
Autofac is designed in such a way that deadlocks won’t occur in normal use. This section is a guide for maintainers or extension writers.
Locks may be acquired in the following order:
A thread holding a lock for any of the following may not acquire any further locks:
A thread holding the lock for a
LifetimeScopemay subsequently acquire the lock for:
Any of the items listed above