Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In dieser Schnellstartanleitung erstellen Sie eine .NET-Konsolen-App, die manuell eine ServiceCollection und ein entsprechendes ServiceProvider erstellt. Sie lernen, wie Sie mithilfe der Abhängigkeitsinjektion (Dependency Injection, DI) Dienste registrieren und auflösen. In diesem Artikel wird das NuGet-Paket "Microsoft.Extensions.DependencyInjection NuGet" verwendet, um die Grundlagen von DI in .NET zu veranschaulichen.
Hinweis
In diesem Artikel werden die generischen Hostfeatures nicht genutzt. Eine ausführlichere Anleitung finden Sie unter Verwenden der Abhängigkeitsinjektion in .NET.
Get started
Erstellen Sie zunächst eine neue .NET-Konsolenanwendung mit dem Namen DI.Basics. Wählen Sie in Visual Studio Datei > Neu > Projekt, oder geben Sie mithilfe der .NET CLIdotnet new console ein.
Fügen Sie als Nächstes einen Paketverweis auf microsoft.Extensions.DependencyInjection in der Projektdatei hinzu. Stellen Sie nach dem Hinzufügen des Pakets sicher, dass das Projekt dem folgenden XML der DATEI DI.Basics.csproj ähnelt:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.5" />
</ItemGroup>
</Project>
Allgemeine Informationen zur Abhängigkeitsinjektion
Die Abhängigkeitseinfügung ist ein Entwurfsmuster, das Sie verwenden können, um hartcodierte Abhängigkeiten zu entfernen und ihre Anwendung besser zu verwalten und zu testen. DI ist eine Technik zum Erreichen von Inversion of Control (IoC) zwischen Klassen und ihren Abhängigkeiten.
Das NuGet-Paket "Microsoft.Extensions.DependencyInjection.Abstractions NuGet" definiert die Abstraktionen für DI in .NET:
- IServiceCollection: Definiert einen Vertrag für eine Sammlung von Dienstdeskriptoren.
- IServiceProvider: Definiert einen Mechanismus zum Abrufen eines Dienstobjekts.
- ServiceDescriptor: Beschreibt einen Dienst mit dem Diensttyp, der Implementierung und der Lebensdauer.
In .NET verwalten Sie DI, indem Sie Dienste hinzufügen und in einer IServiceCollection. Rufen Sie nach dem Registrieren von Diensten die BuildServiceProvider Methode auf, um eine IServiceProvider Instanz zu erstellen. Der IServiceProvider Dient als Container für alle registrierten Dienste, und Sie verwenden ihn, um Dienste aufzulösen.
Erstellen von Beispieldiensten
Nicht alle Dienste sind gleich. Einige Dienste erfordern jedes Mal eine neue Instanz, wenn der Dienstcontainer sie erhält (transient), während andere für einzelne Anfragen (Scoped) oder für die gesamte Lebensdauer der App (Singleton) bereitgestellt werden sollten. Weitere Informationen zu Dienstlebensdauern finden Sie unter Dienstlebensdauer.
Ebenso machen einige Dienste nur einen konkreten Typ verfügbar, während andere als Vertrag zwischen einer Schnittstelle und einem Implementierungstyp ausgedrückt werden. Sie erstellen mehrere Varianten von Diensten, um diese Konzepte zu veranschaulichen.
Erstellen Sie eine neue C#-Datei mit dem Namen IConsole.cs , und fügen Sie den folgenden Code hinzu:
public interface IConsole
{
void WriteLine(string message);
}
Diese Datei definiert eine IConsole Schnittstelle, die eine einzelne Methode verfügbar macht. WriteLine Erstellen Sie als Nächstes eine neue C#-Datei mit dem Namen DefaultConsole.cs , und fügen Sie den folgenden Code hinzu:
internal sealed class DefaultConsole : IConsole
{
public bool IsEnabled { get; set; } = true;
void IConsole.WriteLine(string message)
{
if (IsEnabled is false)
{
return;
}
Console.WriteLine(message);
}
}
Der vorangehende Code stellt die Standardimplementierung der IConsole Schnittstelle dar. Die Methode WriteLine schreibt bedingt in die Konsole IsEnabled basierend auf der Eigenschaft.
Tipp
Die Benennung einer Implementierung ist eine Wahl, mit der sich Ihr Entwicklerteam einigen sollte. Das Default Präfix ist eine gängige Konvention, um eine Standardimplementierung einer Schnittstelle anzugeben, ist jedoch nicht erforderlich.
Erstellen Sie als Nächstes eine IGreetingService.cs Datei, und fügen Sie den folgenden C#-Code hinzu:
public interface IGreetingService
{
string Greet(string name);
}
Fügen Sie dann eine neue C#-Datei namens DefaultGreetingService.cs hinzu , und fügen Sie den folgenden Code hinzu:
internal sealed class DefaultGreetingService(
IConsole console) : IGreetingService
{
public string Greet(string name)
{
var greeting = $"Hello, {name}!";
console.WriteLine(greeting);
return greeting;
}
}
Der vorangehende Code stellt die Standardimplementierung der IGreetingService Schnittstelle dar. Für die Dienstimplementierung ist ein IConsole primärer Konstruktorparameter erforderlich. Die Greet-Methode:
- Erstellt einen
greeting, wenn dernamegegeben ist. - Ruft die
WriteLineMethode für dieIConsoleInstanz auf. - Gibt
greetingan den Aufrufer zurück.
Die DefaultGreetingService Klasse zeigt, dass Sie seal Dienstimplementierungen verwenden können, um die Vererbung zu verhindern, und internal den Zugriff auf die Assembly einschränken.
Der letzte zu erstellende Dienst ist die FarewellService.cs Datei. Fügen Sie den folgenden C#-Code hinzu, bevor Sie fortfahren:
public class FarewellService(IConsole console)
{
public string SayGoodbye(string name)
{
var farewell = $"Goodbye, {name}!";
console.WriteLine(farewell);
return farewell;
}
}
Dies FarewellService stellt einen konkreten Typ dar, keine Schnittstelle. Sie sollten sie public deklarieren, um sie für Verbraucher zugänglich zu machen. Im Gegensatz zu anderen Dienstimplementierungstypen, die Sie als internal und sealed deklarieren, veranschaulicht dieser Code, dass nicht alle Dienste Schnittstellen sein müssen.
Aktualisieren der Program Klasse
Öffnen Sie die Program.cs Datei, und ersetzen Sie den vorhandenen Code durch den folgenden C#-Code:
using Microsoft.Extensions.DependencyInjection;
// 1. Create the service collection.
var services = new ServiceCollection();
// 2. Register (add and configure) the services.
services.AddSingleton<IConsole>(
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
});
services.AddSingleton<IGreetingService, DefaultGreetingService>();
services.AddSingleton<FarewellService>();
// 3. Build the service provider from the service collection.
var serviceProvider = services.BuildServiceProvider();
// 4. Resolve the services that you need.
var greetingService = serviceProvider.GetRequiredService<IGreetingService>();
var farewellService = serviceProvider.GetRequiredService<FarewellService>();
// 5. Use the services
var greeting = greetingService.Greet("David");
var farewell = farewellService.SayGoodbye("David");
Im vorangehenden Code wird veranschaulicht, wie:
- Erstellen Sie eine neue
ServiceCollectionInstanz. - Registrieren und Konfigurieren von Diensten im
ServiceCollection:- Der
IConsoleDienst mithilfe der Implementierungs-Factory-Überladung. Gibt einenDefaultConsoleTyp zurück, bei dem die EigenschaftIsEnabledauftruefestgelegt ist. - Der
IGreetingServiceDienst mit einem entsprechenden Implementierungstyp vonDefaultGreetingService. - Der
FarewellServiceDienst als konkreter Typ.
- Der
- Erstellen Sie das
ServiceProvideraus demServiceCollection. - Lösen Sie die
IGreetingService- undFarewellService-Dienste auf. - Verwenden Sie die aufgelösten Dienste, um eine Person namens
Davidzu begrüßen und zu verabschieden.
Wenn Sie die IsEnabled-Eigenschaft des DefaultConsole auf false aktualisieren, lassen die Greet- und SayGoodbye-Methoden das Schreiben der resultierenden Meldungen auf die Konsole aus. Diese Änderung verdeutlicht, dass der IConsole Dienst in die IGreetingService und FarewellService Dienste als Abhängigkeit injiziert wird, was das Verhalten der App beeinflusst.
Alle diese Dienste werden als Singletons registriert. Für dieses Beispiel funktioniert es identisch, wenn Sie sie als vorübergehende oder bereichsbezogene Dienste registrieren.
Von Bedeutung
In diesem künstlichen Beispiel spielen die Dienstlebensdauern keine Rolle. Berücksichtigen Sie in einer realen Anwendung sorgfältig die Lebensdauer der einzelnen Dienste.
Führen Sie die Beispielanwendung aus
Um die Beispiel-App auszuführen, drücken Sie F5 in Visual Studio oder Visual Studio Code, oder führen Sie den dotnet run Befehl im Terminal aus. Nachdem die App abgeschlossen ist, wird das folgende Ergebnis angezeigt:
Hello, David!
Goodbye, David!
Dienstdeskriptoren
Die am häufigsten verwendeten APIs zum Hinzufügen von Diensten zu ServiceCollection sind generische Erweiterungsmethoden mit lebensdauerbezogenen Namen, z. B.:
AddSingleton<TService>AddTransient<TService>AddScoped<TService>
Diese Methoden sind Komfortmethoden, die eine ServiceDescriptor Instanz erstellen und sie zu der ServiceCollection hinzufügen. Dies ServiceDescriptor ist eine einfache Klasse, die einen Dienst mit seinem Diensttyp, Implementierungstyp und Lebensdauer beschreibt. Es kann auch Implementierungsfabriken und Instanzen beschreiben.
Für jeden Dienst, den Sie im ServiceCollection registriert haben, können Sie stattdessen die Add-Methode direkt mit einer ServiceDescriptor-Instanz aufrufen. Betrachten Sie die folgenden Beispiele:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IConsole),
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
},
lifetime: ServiceLifetime.Singleton));
Der vorangehende Code entspricht der Registrierung des IConsole Diensts in der ServiceCollection. Die Add Methode fügt eine ServiceDescriptor Instanz hinzu, die den IConsole Dienst beschreibt. Die statische Methode ServiceDescriptor.Describe delegiert an verschiedene ServiceDescriptor Konstruktoren. Berücksichtigen Sie den entsprechenden Code für den IGreetingService Dienst:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IGreetingService),
implementationType: typeof(DefaultGreetingService),
lifetime: ServiceLifetime.Singleton));
Der vorangehende Code beschreibt den IGreetingService Dienst mit dem Diensttyp, dem Implementierungstyp und der Lebensdauer. Berücksichtigen Sie schließlich den entsprechenden Code für den FarewellService Dienst:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(FarewellService),
implementationType: typeof(FarewellService),
lifetime: ServiceLifetime.Singleton));
Der vorangehende Code beschreibt den konkreten FarewellService Typ sowohl als Dienst- als auch als Implementierungstypen. Der Dienst wird als Singleton-Dienst registriert.