Autofac 9.1.0
Yesterday I released Autofac 9.1.0. It’s listed as a minor release - 0.X.0 semver increment - because it’s all new, backwards-compatible features, but it’s actually pretty big, I think.
AnyKey Support
Autofac now natively supports the concept of AnyKey. It behaves the same way AnyKey works in Microsoft.Extensions.DependencyInjection, but it is native to Autofac directly. The unit tests here show some very detailed examples of usage, but on a high level:
var builder = new ContainerBuilder();
builder.RegisterType<Service>().Keyed<IService>(KeyedService.AnyKey);
var container = builder.Build();
// Registering as AnyKey allows it to respond to... any key!
var service = container.ResolveKeyed<IService>("service1");
As noted, it behaves like AnyKey in Microsoft.Extensions.DependencyInjection, so there are some “rules” around when AnyKey will work and when it won’t.
- You can resolve a single instance and
AnyKeywill be a fallback. If you resolve a single instance of a service and use a key that you haven’t otherwise registered, anAnyKeyservice can provide that instance. - You can resolve a collection using
AnyKey. This allows you to get all keyed services of a certain type, but it will not include the services registered withAnyKey- only services registered with a specific key. AnyKeyworks with singletons. When you register anAnyKeyservice as a singleton, a different instance of that service will be cached for each key under which it’s resolved. Beware of this - if you’re not paying attention, it could lead to a memory leak.- Registration order is important. As always, last-in-wins. If you register a lot of
AnyKeyservices, the last one registered for the given type will be the one you get when you resolve.
Here are some examples showing usage:
var builder = new ContainerBuilder();
builder.RegisterType<Service1>().Keyed<IService>(KeyedService.AnyKey);
builder.RegisterType<Service2>().Keyed<IService>("a");
builder.RegisterType<Service3>().Keyed<IService>("b");
var container = builder.Build();
// This will ONLY get Service2 and Service3 - things registered with explicit
// keys. It will NOT return Service1, registered with AnyKey.
var allServices = container.ResolveKeyed<IEnumerable<IService>>(KeyedService.AnyKey)
// THIS WILL THROW: You can't resolve a single instance using AnyKey.
_ = container.ResolveKeyed<IService>(KeyedService.AnyKey);
// This will get you the AnyKey service because no specific keyed service was
// registered with `other-key`.
var noRegisteredKey = container.ResolveKeyed<IService>("other-key");
Again, check out the unit tests for some robust examples.
Inject Service Key Into Constructors
The new [ServiceKey] attribute allows you to inject the service key provided during resolution. This is handy in conjunction with AnyKey and is also similar to the construct in Microsoft.Extensions.DependencyInjection, but with native Autofac.
First, mark up your class to take the constructor parameter.
public class Service : IService
{
private readonly string _id;
public Service([ServiceKey] string id) => _id = id;
}
Then when you resolve the class, the service key will automatically be injected.
You can also make use of this in a lambda registration.
var builder = new ContainerBuilder();
builder.Register<Service>((ctx, p) => {
var key = p.TryGetKeyedServiceKey(out string value) ? value : null;
return new Service(key);
}).Keyed<Service>(KeyedService.AnyKey);
Metrics
Some metrics have been introduced that can allow you to capture counters on how long middleware is taking, how often lock contention occurs, and so on.
Set the AUTOFAC_METRICS environment variable in your process to true or 1 to enable this feature. You can see the set of counters that will become available here.
⚠️ This is NOT FREE. Collecting counters and metrics will incur a performance hit, so it’s not something you want to leave on in production.
General Performance Improvements
A pass over the whole system was made with an eye to trying to claw back some performance. Some additional caching was introduced to help reduce lookups and calculations of reflection data; and a few hot-path optimizations were made for the common situations.
A Personal Note
This is probably the biggest Autofac update made in quite some time - new features, some perf fixes, some metrics - and, with that, I really don’t have any active assisting project maintainers, so it was all just me. I’m pretty proud of this one. I have been suffering from maintainer burnout for a while, but I’ve got a little of my energy back lately and, honestly, it’s due to AI.
I used Codex and Claude Opus on this latest set of changes to help me out and do some of the heavy lifting. Don’t get me wrong, I reviewed all of what was output, but it was so energizing to be able to tell something else to go look for changes, dig for performance optimization opportunities, and validate them. I could create a robust set of tests (or, in some cases, adapt existing Microsoft container compatibility tests) to guide implementation and basically say, “Make it pass the tests.” I can safely say I would not have been able to deliver this new set of functionality in any near future without tools like that. Between time constraints and flagging motivation, it wouldn’t have happened.
I’m not at “just vibe code everything” level and I’m definitely not ready for Gas Town, but I see the value here and it counters some of the burnout.



