.NET 8 Dependency Injection Changes: Keyed Services
Keyed Services in .NET 8
It has been quite some time since my last post on dependency injection (DI). In it I tried to talk a bit about the history of DI (or dependency resolution); now, a change was introduced in .NET 8: named (or keyed) services! Essentially, it consists of the possibility to register multiple times the same type under different names, and to inject a specific type/name combo.
To make this possible, a new interface is introduced, IKeyedServiceProvider, which extends our old friend IServiceProvider with two new methods:
- object? GetKeyedService(Type serviceType, object? serviceKey)
- object GetRequiredKeyedService(Type serviceType, object? serviceKey)
I guess these are pretty straightforward. In order to register objects we have overloads that take keys on IServiceCollection, for example, for the singleton lifetime:
builder.Services.AddKeyedSingleton<IMyService, AService>("a");
builder.Services.AddKeyedSingleton<IMyService, BService>("b");
Funny enough, the key is an object, not a string...
And to inject, we have a new attribute, [FromKeyedServices]:
public IActionResult Get([FromKeyedServices("a")] IMyService svc) { ... }
By default, if you pass an empty string as the key, you will get the default, no-key, implementation.
I think this is a great idea, as it gives you more flexibility: if you don't need it, by all means, don't use it, but if you do, hey, it's a great addition!
One thing, however, that is missing, is the possibility to set the key on a [ServiceFilter]. As of know, it can only take the type.