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 Visual Studióban válassza a Fájl > új > projekt lehetőséget, vagy a .NET CLI használatával írja be a következőt dotnet new console:

Ezután adjon hozzá egy csomaghivatkozást a Microsoft.Extensions.DependencyInjection fájlhoz a projektfájlban. A csomag hozzáadása után 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.11" />
  </ItemGroup>

</Project>

A függőséginjektálás alapjai

A függőséginjektálás egy tervezési minta, amellyel eltávolíthatja a szigorúan kódolt függőségeket, és karbantarthatóbbá és tesztelhetőbbé teheti az alkalmazást. 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 Microsoft.Extensions.DependencyInjection.Absztrakciók NuGet-csomag a DI absztrakcióit határozza meg a .NET-ben:

  • 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 úgy kezelheti, hogy szolgáltatásokat ad hozzá, és konfigurálja őket egy IServiceCollection. A szolgáltatások regisztrálása után hívja meg a BuildServiceProvider metódust egy IServiceProvider példány létrehozásához. A IServiceProvider rendszer tárolóként működik az összes regisztrált szolgáltatáshoz, ön pedig a szolgáltatások feloldására használja.

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 dönté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 DefaultGreetingService osztály bemutatja, hogy seal szolgáltatás-implementációkat használva megakadályozhatja az öröklést, és internal korlátozhatja a szerelvényhez való hozzáférést.

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. Deklarálnia kell public, hogy akadálymentessé váljon a fogyasztók számára. A többi, ön által internalsealeddeklarált szolgáltatás-implementációs típustól eltérően ez a kód azt mutatja, hogy nem minden szolgáltatásnak kell interfésznek lennie.

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ő kód bemutatja, hogyan:

  • 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 szolgáltatás a implementálási gyár túlterhelésével. Adjon vissza egy DefaultConsole típust, amelynek IsEnabled tulajdonsága true.
    • A IGreetingService szolgáltatás, amely a megfelelő implementációs típussal DefaultGreetingService rendelkezik.
    • A FarewellService szolgáltatás, mint konkrét típus.
  • 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ágát a DefaultConsole értékére false, a Greet és SayGoodbye metódusok kihagyják az eredményül kapott üzenetek írását a konzolra. Ez a módosítás azt mutatja be, hogy a IConsole szolgáltatás függőségként van injektálva a IGreetingService és FarewellService szolgáltatásokba, amelyek befolyásolják az alkalmazás viselkedését.

Ezek a szolgáltatások önállóan vannak regisztrálva. Ebben a mintában ugyanúgy működik, ha átmeneti vagy hatókörű szolgáltatásként regisztrálja őket.

Fontos

Ebben a példában a szolgáltatás élettartama nem számít. Egy valós alkalmazásban gondosan vegye figyelembe 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ő kimenet jelenik meg:

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.

Az egyes ServiceCollection regisztrált szolgáltatás esetében 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ódus hozzáad egy ServiceDescriptor példányt, amely leírja a IConsole szolgáltatást. 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