Neu in .NET 8.0 [15]: GeschlĂĽsselte Dienste bei der Dependency Injection
Der Dependency-Injection-Container unterstĂĽtzt nun auch die Angabe von SchlĂĽssel zur Unterscheidung von Instanzen.
- Dr. Holger Schwichtenberg
Sogenannte "Keyed Dependency Injection Services" sind neu in .NET 8.0. Hierbei kann bei der Konfiguration des Dependency Injection-Containers ein zusätzliches Objekt angegeben werden, auf den der User Bezug nehmen muss.
Beim BefĂĽllen des Containers verwendet man:
services.AddKeyedSingleton<Klasse>(SchlĂĽssel);
oder
services.AddKeyedSingleton<Schnittstelle, Klasse>(SchlĂĽssel);
Mit [FromKeyedServices("remote")]
kann eine Instanz im Dependency-Injection-Container im Konstruktor eine geschlĂĽsselte Instanz einer anderen Klasse anfordern. Imperativ geht es per serviceProvider.GetKeyedService<T>(SchlĂĽssel)
. Bei einem geschlĂĽsselten Dienst funktioniert das bisher schon verfĂĽgbare serviceProvider.GetRequiredService<T>()
nicht.
Das folgende Beispiel zeigt Zeichenketten als SchlĂĽssel zur Unterscheidung zwischen zwei verschiedenen Implementierungen einer Schnittstelle mit Namen IDataProvider
.
using ITVisions;
using Microsoft.Extensions.DependencyInjection;
namespace NET8_Console;
interface IDataProvider
{
public string Name { get; set; }
public List<Object> GetData();
}
class LocalData : IDataProvider
{
public string Name { get; set; } = "Lokale Daten";
public List<Object> GetData()
{
return new List<Object>(); // irgendwas Lokales }
}
}
class RemoteData : IDataProvider
{
public string Name { get; set; } = "Daten von WebAPI";
public List<Object> GetData()
{
return new List<Object>(); // irgendwas vom WebAPI }
}
}
class LocalDataConsumer([FromKeyedServices("local")]
IDataProvider data)
{
public override string ToString()
{
return data.Name + ": " + data.GetData().Count + " Datensätze!";
}
}
class RemoteDataConsumer([FromKeyedServices("remote")]
IDataProvider data)
{
public override string ToString()
{
return data.Name + ": " + data.GetData().Count + " Datensätze!";
}
}
class FCL_DI
{
/// <summary>
/// Dependency Injection mit SchlĂĽsseln
/// Geht auch in Blazor mit [Inject],
/// aber in .NET 8.0 noch nicht mit @inject :-(
/// </summary>
public void Run()
{
#region DI-Container konfigurieren
var services = new ServiceCollection();
services.AddSingleton<LocalDataConsumer>();
services.AddSingleton<RemoteDataConsumer>();
// Neu: Angabe von SchlĂĽsseln bei Add...()
// --> können beliebige Objekte sein!
services.AddKeyedSingleton<IDataProvider, LocalData>("local");
services.AddKeyedSingleton<IDataProvider, RemoteData>("remote");
var serviceProvider = services.BuildServiceProvider();
#endregion
#region DI nutzen
// Das geht nicht, da kein SchlĂĽssel angegeben!
try
{
var service =
serviceProvider.GetRequiredService<IDataProvider>();
}
catch (Exception ex)
{
// 'No service for type 'NET8_Console.IDataProvider'
// has been registered.'
CUI.PrintError(ex.Message);
}
var service1 =
serviceProvider.GetKeyedService<IDataProvider>("local");
Console.WriteLine(service1.Name); // Lokale Daten
Console.WriteLine(service1.GetData().Count); // Lokale Daten
var service2 =
serviceProvider.GetKeyedService<IDataProvider>("remote");
Console.WriteLine(service2.Name); // Daten von WebAPI
Console.WriteLine(service2.GetData().Count); // Lokale Daten
var service3 =
serviceProvider.GetRequiredService<RemoteDataConsumer>();
Console.WriteLine(service3.ToString()); // Daten von WebAPI
}
#endregion
}
In Razor Components in ASP.NET Core Blazor kann man bei der Annotation [Inject]
nun auch einen SchlĂĽsselnamen angeben wie beispielsweise
[Inject(Key="remote")]
public IDataProvider MeinDataProvider { get; set; }
Allerdings fehlt noch die Fähigkeit, dies bei der @inject
-Direktive innerhalb der Razor-Template-Syntax zu nutzen.
(rme)