Course Content
ASP.NET Core Web API Fundamentials
0/2
Method Safety And Method Idempotency
0/1
Working With OPTIONS and HEAD Requests
0/2
Root Document in ASP.NET Core Web API
0/1
Ultimate ASP.NET Core Web API

Keyed services are a new addition to .NET 8 and a long-requested feature that has finally arrived. This new feature allows us to register multiple implementations of the same type by specific keys. We can then use those keys to tell our application which implementation to use explicitly. Keyed services come in handy when we have an interface with different implementations that we want to use in our application, especially when we need to use several of those implementations in different places in our application at the same time. So, in our application, we have only registered the PlayerGenerator service, but let’s add the BetterPlayerGenerator service registration as well:

builder.Services.AddScoped<IPlayerGenerator, PlayerGenerator>();
builder.Services.AddScoped<IPlayerGenerator, BetterPlayerGenerator>();

Now, if we run the app, and send the same request, we will get this result:

{
  "name": "Better - Jon Irenicus",
  "gender": 0,
  "age": 25,
  "hairColor": 2,
  "strength": 11,
  "race": "Better - Human"
}

Even though we have both services registered, and the interface injected into our controller:

private readonly IPlayerGenerator _playerGenerator;

public GamesController(IPlayerGenerator playerGenerator)
{
    _playerGenerator = playerGenerator;
}

We get the Better Player’s data. This is the case because this service is registered the last. With the implementation as is, we can’t switch between services – well, there are some advanced techniques to do that, but let’s see how keyed services help us with this. Let’s modify the Program class implementation:

builder.Services.AddKeyedScoped<IPlayerGenerator, PlayerGenerator>("player");
builder.Services.AddKeyedScoped<IPlayerGenerator, BetterPlayerGenerator>("betterPlayer");

As you see, now, we are using the AddKeyedScoped method instead of the AddScoped method, and we also provide the “serviceKey” argument for each registration. Yes, this means, we also have the AddKeyedSingleton and the AddKeyedTransient methods to register keyed services with different lifetimes. Now, we have to modify the controller logic:

private readonly IPlayerGenerator _playerGenerator;

public GamesController([FromKeyedServices("player")]IPlayerGenerator playerGenerator)
{
    _playerGenerator = playerGenerator;
}

We are doing the same constructor injection, just this time, we are using the [FromKeyedServices] attribute and provide the “serviceKey” value. This is the value we used to register the specific service we want to resolve here. Now, we can run the app, and verify our result:

{
  "name": "Dynaheir",
  "gender": 1,
  "age": 21,
  "hairColor": 5,
  "strength": 14,
  "race": "Human"
}

We get the player’s JSON data as a result. Of course, if we simply replace the key in the constructor:

public GamesController([FromKeyedServices("betterPlayer")]IPlayerGenerator playerGenerator)
{
    _playerGenerator = playerGenerator;
}

We will get a better player’s JSON data as a result. Excellent. With all this knowledge about dependency injection in .NET, we can continue with our main application and introduce the logger service.

0% Complete