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.

In Pocket speichern vorlesen Druckansicht

(Bild: rawf8/Shutterstock.com)

Lesezeit: 1 Min.
Von
  • 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.

Der Dotnet-Doktor – Holger Schwichtenberg

Dr. Holger Schwichtenberg ist technischer Leiter des Expertennetzwerks www.IT-Visions.de, das mit 53 renommierten Experten zahlreiche mittlere und große Unternehmen durch Beratungen und Schulungen sowie bei der Softwareentwicklung unterstützt. Durch seine Auftritte auf zahlreichen nationalen und internationalen Fachkonferenzen sowie mehr als 90 Fachbücher und mehr als 1500 Fachartikel gehört Holger Schwichtenberg zu den bekanntesten Experten für .NET und Webtechniken in Deutschland.

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)