A függőséginjektálás alapjai a .NET-ben
Ebben a cikkben egy .NET-konzolalkalmazást hoz létre, amely manuálisan hoz létre egy és egy megfelelőt ServiceCollection ServiceProvider. Megtudhatja, hogyan regisztrálhatja és oldhatja fel a szolgáltatásokat függőséginjektálás (DI) használatával. Ez a cikk a Microsoft.Extensions.DependencyInjection NuGet csomag használatával mutatja be a DI alapjait a .NET-ben.
Feljegyzés
Ez a cikk nem használja ki az általános gazdagép funkcióit. Átfogóbb útmutatóért lásd : Függőséginjektálás használata a .NET-ben.
Első lépések
Első lépésként hozzon létre egy DI.Basics nevű új .NET-konzolalkalmazást. A konzolprojektek létrehozásának néhány leggyakoribb módszerére az alábbi listában hivatkozunk:
- Visual Studio: File > New > Project menu.
- A Visual Studio Code és a C# Dev Kit bővítménye: Megoldáskezelő menüpont.
- .NET CLI:
dotnet new console
parancs a terminálban.
A csomaghivatkozást hozzá kell adnia a Microsoft.Extensions.DependencyInjection fájlhoz a projektfájlban. A megközelítéstől függetlenül győződjön meg arról, hogy a projekt a DI.Basics.csproj fájl alábbi XML-fájljához hasonlít:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
</ItemGroup>
</Project>
A függőséginjektálás alapjai
A függőséginjektálás egy olyan tervezési minta, amely lehetővé teszi a szigorúan kódolt függőségek eltávolítását, és az alkalmazás karbantarthatóbbá és tesztelhetőbbé tétele. A DI az osztályok és függőségeik közötti irányítás inverziójának (IoC) elérésére szolgáló technika.
A .NET-beli DI absztrakciói a Microsoft.Extensions.DependencyInjection.Abstractions NuGet csomagban vannak definiálva:
- IServiceCollection: Szolgáltatásleírók gyűjteményére vonatkozó szerződést határoz meg.
- IServiceProvider: Egy szolgáltatásobjektum lekérésének mechanizmusát határozza meg.
- ServiceDescriptor: Egy szolgáltatástípussal, megvalósítással és élettartammal rendelkező szolgáltatást ír le.
A .NET-ben a diát szolgáltatások hozzáadásával és konfigurálásával kezeli a rendszer.IServiceCollection
A szolgáltatások regisztrálása után a rendszer meghívja a BuildServiceProvider metódustIServiceProvider
. A IServiceProvider
rendszer az összes regisztrált szolgáltatás tárolójaként működik, és a szolgáltatások feloldására szolgál.
Szolgáltatások létrehozása example
Nem minden szolgáltatás jön létre egyenlően. Egyes szolgáltatásokhoz minden alkalommal új példányra van szükség, amikor a szolgáltatástároló lekéri őket (transient), míg másokat meg kell osztani a kérések között (scoped) vagy az alkalmazás teljes élettartama alatt (singleton). A szolgáltatás élettartamával kapcsolatos további információkért tekintse meg a szolgáltatás élettartamait.
Hasonlóképpen, egyes szolgáltatások csak konkrét típusokat fednek fel, míg mások egy interfész és egy megvalósítási típus közötti szerződésként vannak kifejezve. Számos szolgáltatásváltozatot hozhat létre ezeknek a fogalmaknak a bemutatásához.
Hozzon létre egy IConsole.cs nevű új C#-fájlt, és adja hozzá a következő kódot:
public interface IConsole
{
void WriteLine(string message);
}
Ez a fájl egy IConsole
olyan felületet határoz meg, amely egyetlen metódust tesz elérhetővé. WriteLine
Ezután hozzon létre egy DefaultConsole.cs nevű új C#-fájlt, és adja hozzá a következő kódot:
internal sealed class DefaultConsole : IConsole
{
public bool IsEnabled { get; set; } = true;
void IConsole.WriteLine(string message)
{
if (IsEnabled is false)
{
return;
}
Console.WriteLine(message);
}
}
Az előző kód a felület alapértelmezett implementációját IConsole
jelöli. A WriteLine
metódus feltételesen a tulajdonság alapján ír a konzolra IsEnabled
.
Tipp.
Az implementáció elnevezése olyan választás, amellyel a fejlesztői csapatnak egyet kell értenie. Az Default
előtag egy általános konvenció, amely egy interfész alapértelmezett implementációját jelzi, de nem kötelező.
Ezután hozzon létre egy IGreetingService.cs fájlt, és adja hozzá a következő C#-kódot:
public interface IGreetingService
{
string Greet(string name);
}
Ezután vegyen fel egy DefaultGreetingService.cs nevű új C#-fájlt, és adja hozzá a következő kódot:
internal sealed class DefaultGreetingService(
IConsole console) : IGreetingService
{
public string Greet(string name)
{
var greeting = $"Hello, {name}!";
console.WriteLine(greeting);
return greeting;
}
}
Az előző kód a felület alapértelmezett implementációját IGreetingService
jelöli. A szolgáltatás implementálásához elsődleges konstruktorparaméterre van szükség IConsole
. A Greet
módszer:
- Létrehoz egy
greeting
adott elemet.name
- Meghívja a
WriteLine
metódust aIConsole
példányon. - Visszaadja a
greeting
hívónak.
Az utolsó létrehozandó szolgáltatás a FarewellService.cs fájl, a folytatás előtt adja hozzá a következő C#-kódot:
public class FarewellService(IConsole console)
{
public string SayGoodbye(string name)
{
var farewell = $"Goodbye, {name}!";
console.WriteLine(farewell);
return farewell;
}
}
Ez FarewellService
konkrét típust jelöl, nem interfészt. Be kell jelenteni, public
hogy az elérhető legyen a fogyasztók számára. Ellentétben más, deklarált internal
sealed
szolgáltatás-implementációs típusokkal, ez a kód azt mutatja, hogy nem minden szolgáltatásnak kell interfésznek lennie. Azt is megmutatja, hogy a szolgáltatás implementációi megakadályozhatják sealed
az öröklést, és internal
korlátozhatják a szerelvényhez való hozzáférést.
Az Program
osztály frissítése
Nyissa meg a Program.cs fájlt, és cserélje le a meglévő kódot a következő C#-kódra:
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");
Az előző frissített kód a következő útmutatót mutatja be:
- Hozzon létre egy új
ServiceCollection
példányt. - Szolgáltatások regisztrálása és konfigurálása a
ServiceCollection
következő helyen:- A
IConsole
implementálási gyár túlterhelése egy "true" értékreIsEnabled
beállított típust ad visszaDefaultConsole
. - A
IGreetingService
rendszer hozzá van adva egy megfelelő implementációs típussalDefaultGreetingService
. - Ez
FarewellService
betontípusként van hozzáadva.
- A
- Hozza létre a
ServiceProvider
következőből:ServiceCollection
. - Oldja fel a szolgáltatásokat és
FarewellService
aIGreetingService
szolgáltatásokat. - A feloldott szolgáltatások használatával köszönthet és búcsúzhat egy elnevezett
David
személytől.
Ha frissíti a IsEnabled
tulajdonságot a DefaultConsole
következőrefalse
, a metódusok és SayGoodbye
a Greet
metódusok nem írnak az eredményül kapott üzenetekre a konzolon. Az ehhez hasonló módosítás segít annak bizonyításában, hogy a IConsole
szolgáltatás az alkalmazások viselkedését befolyásoló függőségként van beszúrva a IGreetingService
szolgáltatásba és FarewellService
a szolgáltatásokba.
Ezen szolgáltatások mindegyike önállóként van regisztrálva, bár ebben a mintában ugyanúgy működik, ha azok mintaként vagy scoped szolgáltatásként transient lettek regisztrálva.
Fontos
Ebben a folyamatban examplea szolgáltatás élettartama nem számít, de egy valós alkalmazásban gondosan figyelembe kell vennie az egyes szolgáltatások élettartamát.
A mintaalkalmazás futtatása
A mintaalkalmazás futtatásához nyomja le az F5 billentyűt a Visual Studióban, a Visual Studio Code-ban, vagy futtassa a dotnet run
parancsot a terminálon. Az alkalmazás befejeződésekor a következő kimenetnek kell megjelennie:
Hello, David!
Goodbye, David!
Szolgáltatásleírók
A szolgáltatások hozzáadásához leggyakrabban használt API-k az ServiceCollection
élettartam által elnevezett általános bővítménymetszeti módszerek, például:
AddSingleton<TService>
AddTransient<TService>
AddScoped<TService>
Ezek a metódusok olyan egyszerű metódusok, amelyek létrehoznak egy példányt ServiceDescriptor , és hozzáadják azt a ServiceCollection
. Ez ServiceDescriptor
egy egyszerű osztály, amely leírja a szolgáltatást a szolgáltatástípusával, implementálási típusával és élettartamával. Emellett a megvalósítási gyárakat és példányokat is deszribeálhatja.
A regisztrált ServiceCollection
szolgáltatások mindegyikéhez közvetlenül meghívhatja a Add
metódust egy ServiceDescriptor
példánysal. Tekintse az alábbi példákat:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IConsole),
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
},
lifetime: ServiceLifetime.Singleton));
Az előző kód megegyezik azzal, ahogyan a IConsole
szolgáltatás regisztrálva lett a ServiceCollection
. A Add
metódus a szolgáltatást leíró példány hozzáadására ServiceDescriptor
IConsole
szolgál. A statikus metódus ServiceDescriptor.Describe
különböző ServiceDescriptor
konstruktorokra delegál. Vegye figyelembe a szolgáltatás egyenértékű kódját IGreetingService
:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IGreetingService),
implementationType: typeof(DefaultGreetingService),
lifetime: ServiceLifetime.Singleton));
Az előző kód a IGreetingService
szolgáltatás típusát, implementálási típusát és élettartamát írja le. Végül vegye figyelembe a szolgáltatás egyenértékű kódját FarewellService
:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(FarewellService),
implementationType: typeof(FarewellService),
lifetime: ServiceLifetime.Singleton));
Az előző kód a konkrét FarewellService
típust a szolgáltatás és a megvalósítás típusaként is leírja. A szolgáltatás szolgáltatásként singleton van regisztrálva.