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)