- Home
- .NET tutorials
- Keyed services in .NET 8 finally sees a dependency injection update
Keyed services in .NET 8 finally sees a dependency injection update
Published: Saturday 16 September 2023
Keyed services in .NET 8 finally brings an update to dependency injection in ASP.NET Core.
A feature that has been included with other .NET IoC containers for many years, keyed services allows us to inject multiple services of the same type but with a different implementation. The key allows us to determine which implementation to use.
C# coding challenges
We'll have a look at how we configure keyed services in ASP.NET Core. In-addition, we'll show you how to use them with MVC, Web API and Minimal API endpoints.
Services we will use in dependency injection
Here are the services and their implementations that we will use in this tutorial to demonstrate how keyed services work.
public interface IOldVehicleService
{
int NoOfWheels { get; }
}
public interface IVehicleService
{
int NoOfWheels { get; }
}
public class CarService : IVehicleService, IOldVehicleService
{
public int NoOfWheels => 4;
}
public class MotorbikeService : IVehicleService, IOldVehicleService
{
public int NoOfWheels => 2;
}
Multiple implementations prior to .NET 8
It was possible to add multiple implementations of the same service prior to .NET 8.
In this instance, we are adding two IOldVehicleService
services to the IoC container. One has the CarService
as it's implementation. The other is MotorbikeService
.
// Program.cs
builder.Services.AddScoped<IOldVehicleService, CarService>();
builder.Services.AddScoped<IOldVehicleService, MotorbikeService>();
However, if we injected IOldVehicleService
as a parameter into a controller's constructor for example, it would reference the last implementation added to the IoC instance.
Here, the IOldVehicleService
would contain the MotorbikeService
class reference.
// VehicleApiController.cs
public class VehicleApiController : Controller
{
private readonly IOldVehicleService _oldVehicleService;
public VehicleApiController (IOldVehicleService oldVehicleService)
{
_oldVehicleService = oldVehicleService; // Would contain the MotorbikeService class reference
}
}
If we wanted to get any other implementations of the same service, we would have to inject an IEnumerable
instance of the service and loop through it to get the correct implementation.
// VehicleApiController.cs
public class VehicleApiController : Controller
{
private readonly IEnumerable<IOldVehicleService> _oldVehicleServices;
public VehicleApiController (IEnumerable<IOldVehicleService> oldVehicleServices)
{
_oldVehicleServices = oldVehicleServices; // Would contain both the CarService and MotorbikeService class references
}
}
Introducing keyed services
Keyed services allows us to separate multiple services with a key (hence the name). It works with singleton, scoped and transient service lifetimes.
The AddKeyedSingleton
, AddKeyedScoped
and AddKeyedTransient
has been added as IServiceCollection
extension methods. All of these methods have a service key parameter which can be any object.
In this instance, we have two IVehicleService
services added to the IoC container. The first is the CarService
and uses car
as the service key. The other is MotorbikeService
which uses motorbike
.
// Program.cs
builder.Services.AddKeyedScoped<IVehicleService, CarService>("car");
builder.Services.AddKeyedScoped<IVehicleService, MotorbikeService>("motorbike");
How to use with Minimal APIs
When injecting the IVehicleService
into an endpoint's parameter, the FromKeyedServices
attribute needs to be prepended to the parameter. This contains the key of the service so the correct implementation is injected.
// Program.cs
app.MapGet("/api/minimal-api", (
[FromKeyedServices("car")] IVehicleService carService,
[FromKeyedServices("motorbike")] IVehicleService motorbikeService
) =>
{
return Results.Ok(new
{
CarWheels = carService.NoOfWheels,
MotorbikeWheels = motorbikeService.NoOfWheels
});
});
The key determines which implementation it needs to use.
How to use with MVC and Web API controllers
The same FromKeyedServices
attribute has to be prepended to the parameter which indicates which implementation to inject.
Here is how it works with a Web API endpoint:
// VehicleApiController.cs
[Route("api/web-api")]
[ApiController]
public class VehicleApiController : Controller
{
[HttpGet("dotnet-8")]
public IActionResult ReturnNoOfWheels(
[FromKeyedServices("car")] IVehicleService carService,
[FromKeyedServices("motorbike")] IVehicleService motorbikeService
)
{
return Ok(new
{
CarWheels = carService.NoOfWheels,
MotorbikeWheels = motorbikeService.NoOfWheels,
});
}
}
The service provider method
It's also possible to use it as part of the IServiceProvider
instance. A new GetRequiredKeyedService
(and GetKeyedService
to avoid exceptions being thrown when null) method has been added to resolve a keyed service.
This contains a parameter to add the key of the service.
// VehicleApiController.cs
[Route("api/web-api")]
[ApiController]
public class VehicleApiController : ControllerBase
{
private readonly IServiceProvider _serviceProvider;
public VehicleApiController(
IServiceProvider serviceProvider
)
{
_serviceProvider = serviceProvider;
}
[HttpGet("dotnet-8-service-provider")]
public IActionResult ReturnNoOfWheelsServiceProvider()
{
var carService = _serviceProvider.GetRequiredKeyedService<IVehicleService>("car");
var motorbikeService = _serviceProvider.GetRequiredKeyedService<IVehicleService>("motorbike");
return Ok(new
{
CarWheels = carService.NoOfWheels,
MotorbikeWheels = motorbikeService.NoOfWheels,
});
}
}
Learn more about keyed services
Watch our video where we talk about keyed services in detail and how to add them to a ASP.NET Core web application in .NET 8.
In-addition, download the code example for this tutorial where you can experiment with keyed services yourself.
How to use keyed services now
This feature has been added to .NET 8 RC 1. This can be used by downloading Visual Studio 2022 preview (make sure it's version 17.8 if you're updating). In-addition, you'll need to download the .NET 8 SDK (RC 1 or later).
When .NET 8 is released in November, you'll be able to update Visual Studio 2022 to version 17.8 and ensure that you have the latest .NET 8 SDK installed.