Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym przewodniku szybkiego startu utworzysz aplikację konsolową na platformie .NET, która ręcznie utworzy ServiceCollection i odpowiadający ServiceProvider. Dowiesz się, jak zarejestrować usługi i rozwiązać je przy użyciu wstrzykiwania zależności (DI). W tym artykule użyto pakietu NuGet Microsoft.Extensions.DependencyInjection , aby zademonstrować podstawy di na platformie .NET.
Uwaga / Notatka
Ten artykuł nie korzysta z funkcji hosta ogólnego . Aby uzyskać bardziej kompleksowy przewodnik, zobacz Use dependency injection in .NET (Używanie wstrzykiwania zależności na platformie .NET).
Wprowadzenie
Aby rozpocząć, utwórz nową aplikację konsolową platformy .NET o nazwie DI.Basics. Niektóre z najbardziej typowych podejść do tworzenia projektu konsoli znajdują się na poniższej liście:
- Visual Studio: menu Nowy > projekt pliku>.
- Visual Studio Code i rozszerzenie C# Dev Kit opcja menu Eksplorator rozwiązań.
-
.NET CLI:
dotnet new consolepolecenie w terminalu.
Należy dodać referencję do pakietu Microsoft.Extensions.DependencyInjection w pliku projektu. Niezależnie od podejścia upewnij się, że projekt przypomina następujący kod XML pliku DI.Basics.csproj :
<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.2" />
</ItemGroup>
</Project>
Podstawy wstrzykiwania zależności
Wstrzykiwanie zależności to wzorzec projektowy, który umożliwia usuwanie trwale zakodowanych zależności i zwiększenie możliwości konserwacji i testowania aplikacji. Di jest techniką osiągnięcia inwersji kontroli (IoC) między klasami i ich zależnościami.
Abstrakcje DI w .NET są zdefiniowane w pakiecie NuGet Microsoft.Extensions.DependencyInjection.Abstractions:
- IServiceCollection: definiuje kontrakt dla kolekcji deskryptorów usług.
- IServiceProvider: definiuje mechanizm pobierania obiektu usługi.
- ServiceDescriptor: Opisuje usługę z jej typem usługi, implementacją i okresem istnienia.
Na platformie .NET zarządza się DI poprzez dodawanie usług i konfigurowanie ich w programie IServiceCollection. Po zarejestrowaniu usług, wystąpienie IServiceProvider jest tworzone przez wywołanie metody BuildServiceProvider.
IServiceProvider działa jako kontener wszystkich zarejestrowanych usług i jest używany do rozwiązywania usług.
Tworzenie przykładowych usług
Nie wszystkie usługi mają tę samą jakość. Niektóre usługi wymagają nowego wystąpienia za każdym razem, gdy kontener usługi je pobiera (tymczasowy), podczas gdy inne powinny być współużytkowane między żądaniami (zasięgu) lub przez cały okres istnienia aplikacji (singleton). Aby uzyskać więcej informacji na temat okresów istnienia usług, zobacz Okresy istnienia usługi.
Podobnie niektóre usługi uwidaczniają tylko konkretny typ, podczas gdy inne są wyrażane jako kontrakt między interfejsem a typem implementacji. Utworzysz kilka odmian usług, aby zademonstrować te pojęcia.
Utwórz nowy plik C# o nazwie IConsole.cs i dodaj następujący kod:
public interface IConsole
{
void WriteLine(string message);
}
Ten plik definiuje IConsole interfejs, który uwidacznia jedną metodę . WriteLine Następnie utwórz nowy plik C# o nazwie DefaultConsole.cs i dodaj następujący kod:
internal sealed class DefaultConsole : IConsole
{
public bool IsEnabled { get; set; } = true;
void IConsole.WriteLine(string message)
{
if (IsEnabled is false)
{
return;
}
Console.WriteLine(message);
}
}
Powyższy kod reprezentuje domyślną implementację interfejsu IConsole . Metoda WriteLine warunkowo zapisuje do konsoli na podstawie właściwości IsEnabled.
Wskazówka
Nazewnictwo implementacji jest wyborem, w jaki zespół deweloperów powinien się zgodzić. Prefiks Default to wspólna konwencja wskazująca domyślną implementację interfejsu, ale nie jest wymagana.
Następnie utwórz plik IGreetingService.cs i dodaj następujący kod w języku C#:
public interface IGreetingService
{
string Greet(string name);
}
Następnie dodaj nowy plik C# o nazwie DefaultGreetingService.cs i dodaj następujący kod:
internal sealed class DefaultGreetingService(
IConsole console) : IGreetingService
{
public string Greet(string name)
{
var greeting = $"Hello, {name}!";
console.WriteLine(greeting);
return greeting;
}
}
Powyższy kod reprezentuje domyślną implementację interfejsu IGreetingService . Implementacja usługi wymaga IConsole jako podstawowego parametru konstruktora. Metoda Greet:
- Tworzy
greetingdanyname. - Wywołuje metodę
WriteLinew wystąpieniuIConsole. - Zwraca element
greetingdo elementu wywołującego.
Ostatnia usługa do utworzenia to plik FarewellService.cs , dodaj następujący kod C#, zanim przejdziesz dalej:
public class FarewellService(IConsole console)
{
public string SayGoodbye(string name)
{
var farewell = $"Goodbye, {name}!";
console.WriteLine(farewell);
return farewell;
}
}
Obiekt FarewellService reprezentuje konkretny typ, a nie interfejs. Należy to zadeklarować jako public, aby było dostępne dla użytkowników. W przeciwieństwie do innych typów implementacji usług, które zostały zadeklarowane jako internal i sealed, ten kod pokazuje, że nie wszystkie usługi muszą być interfejsami. Pokazuje również, że implementacje usług mogą sealed uniemożliwić dziedziczenie i internal ograniczyć dostęp do zestawu.
Program Zaktualizuj klasę
Otwórz plik Program.cs i zastąp istniejący kod następującym kodem c#:
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");
Powyższy zaktualizowany kod przedstawia instrukcje:
- Utwórz nowe
ServiceCollectionwystąpienie. - Rejestrowanie i konfigurowanie usług w programie
ServiceCollection:- Używając przeciążenia fabryki implementacji
IConsole, zwraca się typDefaultConsolez wartościąIsEnabledustawioną natrue. - Element
IGreetingServicejest dodawany z typem implementacji odpowiadającym typowiDefaultGreetingService. - Element
FarewellServicejest dodawany jako typ konkretny.
- Używając przeciążenia fabryki implementacji
- Skompiluj element
ServiceProviderz plikuServiceCollection. - Rozwiąż problemy z usługami
IGreetingServiceiFarewellService. - Skorzystaj ze świadczonych usług, aby powitać i pożegnać się z osobą o imieniu
David.
Jeśli zaktualizujesz właściwość IsEnabled elementu DefaultConsole do false, metody Greet i SayGoodbye pomijają zapisywanie wynikowych komunikatów na konsolę. Taka zmiana pomaga pokazać, że IConsole usługa jest wprowadzana do IGreetingService usług i FarewellService jako zależność , która wpływa na zachowanie aplikacji.
Wszystkie te usługi są rejestrowane jako singletony, chociaż w przypadku tego przykładu działają identycznie, jeśli zostały zarejestrowane jako usługi przejściowe lub objęte zakresem .
Ważne
W tym spisanym przykładzie okresy istnienia usługi nie mają znaczenia, ale w rzeczywistej aplikacji należy dokładnie rozważyć okres istnienia każdej usługi.
Uruchamianie przykładowej aplikacji
Aby uruchomić przykładową aplikację, naciśnij F5 w programie Visual Studio lub Visual Studio Code albo uruchom dotnet run polecenie w terminalu. Po zakończeniu pracy aplikacji powinny zostać wyświetlone następujące dane wyjściowe:
Hello, David!
Goodbye, David!
Deskryptory usług
Najczęściej używane interfejsy API do dodawania usług do ServiceCollection to ogólne metody rozszerzeń określające czas życia, takie jak:
AddSingleton<TService>AddTransient<TService>AddScoped<TService>
Te metody są wygodnymi funkcjami, które tworzą instancję ServiceDescriptor i dodają ją do ServiceCollection. To ServiceDescriptor jest prostą klasą, która opisuje usługę z jej typem usługi, typem implementacji i okresem istnienia. Może również opisywać fabryki i instancje implementacji.
Dla każdej z usług zarejestrowanych w systemie ServiceCollection można zamiast tego bezpośrednio wywołać metodę Add z instancją ServiceDescriptor. Rozważ następujące przykłady:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IConsole),
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
},
lifetime: ServiceLifetime.Singleton));
Powyższy kod jest równoważny temu, jak IConsole usługa została zarejestrowana w ServiceCollection. Metoda Add służy do dodawania wystąpienia ServiceDescriptor opisującego usługę IConsole. Metoda statyczna ServiceDescriptor.Describe deleguje do różnych ServiceDescriptor konstruktorów. Rozważ odpowiedni kod dla IGreetingService usługi:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IGreetingService),
implementationType: typeof(DefaultGreetingService),
lifetime: ServiceLifetime.Singleton));
Powyższy kod opisuje usługę IGreetingService z jej typem usługi, typem implementacji i okresem istnienia. Na koniec rozważ odpowiedni kod dla FarewellService usługi:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(FarewellService),
implementationType: typeof(FarewellService),
lifetime: ServiceLifetime.Singleton));
Powyższy kod opisuje konkretny FarewellService typ zarówno usługi, jak i typów implementacji. Usługa jest zarejestrowana jako pojedyncza usługa.
Zobacz także
- Wstrzykiwanie zależności platformy .NET
- Wskazówki dotyczące wstrzykiwania zależności
- Iniekcja zależności w ASP.NET Core