Megosztás:


Rövid útmutató: A függőséginjektálás alapjai a .NET-ben

Ebben a rövid útmutatóban létrehoz egy .NET konzolalkalmazást, amely manuálisan létrehoz egy ServiceCollection-t és egy hozzá tartozó ServiceProvider-t. 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.

Megjegyzés:

Ez a cikk nem használja ki a generikus host 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:

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>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.2" />
  </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 Szolgáltatások regisztrálása után a IServiceProvider példány a BuildServiceProvider metódus meghívásával épül fel. 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.

Példaszolgáltatások létrehozása

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 (átmeneti), míg másokat meg kell osztani a kérések között (hatókörrel) 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 ír a konzolra a IsEnabled tulajdonság alapján.

Jótanács

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 a megadott name alapján.
  • Meghívja a WriteLine metódust a IConsole 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. Annak érdekében, hogy elérhető legyen a fogyasztók számára, public-ként kell bejelenteni. Ellentétben más, deklarált internalsealedszolgá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 használhatók sealed az öröklés megelőzésére, és internal a szerelvényhez való hozzáférés korlátozására.

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 ServiceCollectionkövetkező helyen:
    • A IConsole implementációs gyár túlterheléssel egy olyan DefaultConsole típust ad vissza, amelynek IsEnabled beállítása true.
    • A IGreetingService hozzáadódik egy megfelelő implementációs típusként a DefaultGreetingService típusúként.
    • Ez FarewellService betontípusként van hozzáadva.
  • ServiceProvider felépítése a ServiceCollection alapján.
  • Hárítsa el a IGreetingService és FarewellService szolgáltatásokat.
  • Használja a feloldott szolgáltatásokat, hogy üdvözölje és elbúcsúzzon egy David névre hallgató személytől.

Ha frissíti a IsEnabled tulajdonságot a DefaultConsole következőre false, akkor a Greet és SayGoodbye metódusok kihagyják az üzenetek konzolra való írását. 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éntIGreetingService a FarewellService szolgáltatásba és 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 átmeneti vagy hatókörű szolgáltatásként lettek regisztrálva .

Fontos

Ebben a példában a szolgáltatás élettartama nem számít, de egy valós alkalmazásban alaposan meg kell fontolnia 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 vagy 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 szerint elnevezett általános kiterjesztési metódusok, mint például:

  • AddSingleton<TService>
  • AddTransient<TService>
  • AddScoped<TService>

Ezek a metódusok kényelmi metódusok, amelyek létrehoznak egy ServiceDescriptor példányt, és hozzáadják a ServiceCollection-hez. 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 leírhatja.

A regisztrált ServiceCollectionszolgáltatások mindegyikénél közvetlenül meghívhatja a Add metódust egy ServiceDescriptor példánnyal. Vegye figyelembe a következő 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 volt a ServiceCollection. A Add metódust egy ServiceDescriptor példány hozzáadására használjuk, amely a IConsole szolgáltatást írja le. 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 egyszeri szolgáltatásként van regisztrálva.

Lásd még