Share via


Oktatóanyag: Függőséginjektálás használata a .NET-ben

Ez az oktatóanyag bemutatja, hogyan használható a függőséginjektálás (DI) a .NET-ben. A Microsoft Extensions használatával a diát szolgáltatások hozzáadásával és konfigurálásával felügyeli egy IServiceCollection. Az IHost interfész elérhetővé teszi a IServiceProvider példányt, amely az összes regisztrált szolgáltatás tárolójaként működik.

Ebben az oktatóanyagban az alábbiakkal fog megismerkedni:

  • Függőséginjektálást használó .NET-konzolalkalmazás létrehozása
  • Általános gazdagép létrehozása és konfigurálása
  • Több felület és megfelelő implementáció írása
  • A szolgáltatás élettartamának és hatókörének használata a DI-hez

Előfeltételek

  • .NET Core 3.1 SDK vagy újabb.
  • Az új .NET-alkalmazások létrehozásának és a NuGet-csomagok telepítésének ismerete.

Új konzolalkalmazás létrehozása

A dotnet új parancsával vagy egy IDE új projektvarázslóval hozzon létre egy új .NET-konzolalkalmazást ConsoleDI.Example Adja hozzá a Microsoft.Extensions.Hosting NuGet-csomagot a projekthez.

Az új konzolalkalmazás projektfájljának az alábbiakhoz kell hasonlítania:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>
    <RootNamespace>ConsoleDI.Example</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
  </ItemGroup>

</Project>

Fontos

Ebben a példában a Microsoft.Extensions.Hosting NuGet csomag szükséges az alkalmazás létrehozásához és futtatásához. Egyes metacsomagok tartalmazhatják a Microsoft.Extensions.Hosting csomagot, ebben az esetben nincs szükség explicit csomaghivatkozásra.

Interfészek hozzáadása

Ebben a mintaalkalmazásban megtudhatja, hogyan kezeli a függőséginjektálás a szolgáltatás élettartamát. Több felületet fog létrehozni, amelyek különböző szolgáltatási élettartamokat jelölnek. Adja hozzá a következő felületeket a projekt gyökérkönyvtárához:

IReportServiceLifetime.cs

using Microsoft.Extensions.DependencyInjection;

namespace ConsoleDI.Example;

public interface IReportServiceLifetime
{
    Guid Id { get; }

    ServiceLifetime Lifetime { get; }
}

Az IReportServiceLifetime interfész a következőket határozza meg:

  • A Guid Id szolgáltatás egyedi azonosítóját képviselő tulajdonság.
  • A ServiceLifetime szolgáltatás élettartamát jelképező tulajdonság.

ÉnExampleTransientService.cs

using Microsoft.Extensions.DependencyInjection;

namespace ConsoleDI.Example;

public interface IExampleTransientService : IReportServiceLifetime
{
    ServiceLifetime IReportServiceLifetime.Lifetime => ServiceLifetime.Transient;
}

ÉnExampleScopedService.cs

using Microsoft.Extensions.DependencyInjection;

namespace ConsoleDI.Example;

public interface IExampleScopedService : IReportServiceLifetime
{
    ServiceLifetime IReportServiceLifetime.Lifetime => ServiceLifetime.Scoped;
}

ÉnExampleSingletonService.cs

using Microsoft.Extensions.DependencyInjection;

namespace ConsoleDI.Example;

public interface IExampleSingletonService : IReportServiceLifetime
{
    ServiceLifetime IReportServiceLifetime.Lifetime => ServiceLifetime.Singleton;
}

A explicit implementálás IReportServiceLifetime.Lifetime összes almappája IReportServiceLifetime alapértelmezés szerint. Például IExampleTransientService explicit módon implementálja IReportServiceLifetime.Lifetime az ServiceLifetime.Transient értéket.

Alapértelmezett implementációk hozzáadása

A példa implementációk mind inicializálják a tulajdonságukat Id a következő eredménnyel Guid.NewGuid(): . Adja hozzá az alábbi alapértelmezett implementációs osztályokat a különböző szolgáltatásokhoz a projekt gyökérkönyvtárához:

ExampleTransientService.cs

namespace ConsoleDI.Example;

internal sealed class ExampleTransientService : IExampleTransientService
{
    Guid IReportServiceLifetime.Id { get; } = Guid.NewGuid();
}

ExampleScopedService.cs

namespace ConsoleDI.Example;

internal sealed class ExampleScopedService : IExampleScopedService
{
    Guid IReportServiceLifetime.Id { get; } = Guid.NewGuid();
}

ExampleSingletonService.cs

namespace ConsoleDI.Example;

internal sealed class ExampleSingletonService : IExampleSingletonService
{
    Guid IReportServiceLifetime.Id { get; } = Guid.NewGuid();
}

Minden implementáció a megfelelő felületként internal sealed van definiálva és implementálva. Például implementálja a ExampleSingletonService következőt IExampleSingletonService: .

Di-t igénylő szolgáltatás hozzáadása

Adja hozzá a következő szolgáltatás-élettartamú riporteri osztályt, amely szolgáltatásként működik a konzolalkalmazásban:

ServiceLifetimeReporter.cs

namespace ConsoleDI.Example;

internal sealed class ServiceLifetimeReporter(
    IExampleTransientService transientService,
    IExampleScopedService scopedService,
    IExampleSingletonService singletonService)
{
    public void ReportServiceLifetimeDetails(string lifetimeDetails)
    {
        Console.WriteLine(lifetimeDetails);

        LogService(transientService, "Always different");
        LogService(scopedService, "Changes only with lifetime");
        LogService(singletonService, "Always the same");
    }

    private static void LogService<T>(T service, string message)
        where T : IReportServiceLifetime =>
        Console.WriteLine(
            $"    {typeof(T).Name}: {service.Id} ({message})");
}

A ServiceLifetimeReporter definíció egy konstruktort határoz meg, amely a fent említett szolgáltatási felületek mindegyikét, azaz IExampleTransientService, IExampleScopedServiceés IExampleSingletonService. Az objektum egyetlen metódust tesz elérhetővé, amely lehetővé teszi a fogyasztó számára, hogy egy adott lifetimeDetails paraméterrel jelentést tegyen a szolgáltatásról. Meghíváskor a metódus naplózza az ReportServiceLifetimeDetails egyes szolgáltatások egyedi azonosítóját a szolgáltatás élettartamára vonatkozó üzenettel. A naplóüzenetek segítenek a szolgáltatás élettartamának megjelenítésében.

Szolgáltatások regisztrálása a DI-hez

Frissítse Program.cs a következő kóddal:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ConsoleDI.Example;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddTransient<IExampleTransientService, ExampleTransientService>();
builder.Services.AddScoped<IExampleScopedService, ExampleScopedService>();
builder.Services.AddSingleton<IExampleSingletonService, ExampleSingletonService>();
builder.Services.AddTransient<ServiceLifetimeReporter>();

using IHost host = builder.Build();

ExemplifyServiceLifetime(host.Services, "Lifetime 1");
ExemplifyServiceLifetime(host.Services, "Lifetime 2");

await host.RunAsync();

static void ExemplifyServiceLifetime(IServiceProvider hostProvider, string lifetime)
{
    using IServiceScope serviceScope = hostProvider.CreateScope();
    IServiceProvider provider = serviceScope.ServiceProvider;
    ServiceLifetimeReporter logger = provider.GetRequiredService<ServiceLifetimeReporter>();
    logger.ReportServiceLifetimeDetails(
        $"{lifetime}: Call 1 to provider.GetRequiredService<ServiceLifetimeReporter>()");

    Console.WriteLine("...");

    logger = provider.GetRequiredService<ServiceLifetimeReporter>();
    logger.ReportServiceLifetimeDetails(
        $"{lifetime}: Call 2 to provider.GetRequiredService<ServiceLifetimeReporter>()");

    Console.WriteLine();
}

Minden services.Add{LIFETIME}<{SERVICE}> bővítménymetódus szolgáltatásokat ad hozzá (és konfigurál). Javasoljuk, hogy az alkalmazások kövessék ezt az egyezményt. Csak akkor helyezzen el bővítménymetodusokat a Microsoft.Extensions.DependencyInjection névtérben, ha hivatalos Microsoft-csomagot szerkesszen. A névtérben Microsoft.Extensions.DependencyInjection definiált bővítménymetelyek:

  • Az IntelliSense további blokkok nélkül using jelenik meg.
  • Csökkentse a szükséges using utasítások számát azon osztályokban vagy Startup osztályokban, ahol ezeket a Program bővítménymetszeteket általában meghívják.

Az alkalmazás:

  • Létrehoz egy példányt IHostBuilder a gazdagépszerkesztő beállításaival.
  • Konfigurálja a szolgáltatásokat, és hozzáadja őket a hozzájuk tartozó szolgáltatási élettartammal.
  • Meghívja Build() és hozzárendeli a példányt IHost.
  • Hívások ExemplifyScoping, átengedés a IHost.Services.

Összefoglalás

Ebben a mintaalkalmazásban számos felületet és megfelelő implementációt hozott létre. Ezek a szolgáltatások egyedileg vannak azonosítva és párosítva egy ServiceLifetime. A mintaalkalmazás bemutatja, hogyan regisztrálhat szolgáltatás-implementációkat egy felületen, és hogyan regisztrálhat tiszta osztályokat háttérfelületek nélkül. A mintaalkalmazás ezután bemutatja, hogyan oldódnak fel a konstruktorparaméterekként definiált függőségek futásidőben.

Az alkalmazás futtatásakor az alábbihoz hasonló kimenet jelenik meg:

// Sample output:
// Lifetime 1: Call 1 to provider.GetRequiredService<ServiceLifetimeReporter>()
//     IExampleTransientService: d08a27fa-87d2-4a06-98d7-2773af886125 (Always different)
//     IExampleScopedService: 402c83c9-b4ed-4be1-b78c-86be1b1d908d (Changes only with lifetime)
//     IExampleSingletonService: a61f1ff4-0b14-4508-bd41-21d852484a7b (Always the same)
// ...
// Lifetime 1: Call 2 to provider.GetRequiredService<ServiceLifetimeReporter>()
//     IExampleTransientService: b43d68fb-2c7b-4a9b-8f02-fc507c164326 (Always different)
//     IExampleScopedService: 402c83c9-b4ed-4be1-b78c-86be1b1d908d (Changes only with lifetime)
//     IExampleSingletonService: a61f1ff4-0b14-4508-bd41-21d852484a7b (Always the same)
// 
// Lifetime 2: Call 1 to provider.GetRequiredService<ServiceLifetimeReporter>()
//     IExampleTransientService: f3856b59-ab3f-4bbd-876f-7bab0013d392 (Always different)
//     IExampleScopedService: bba80089-1157-4041-936d-e96d81dd9d1c (Changes only with lifetime)
//     IExampleSingletonService: a61f1ff4-0b14-4508-bd41-21d852484a7b (Always the same)
// ...
// Lifetime 2: Call 2 to provider.GetRequiredService<ServiceLifetimeReporter>()
//     IExampleTransientService: a8015c6a-08cd-4799-9ec3-2f2af9cbbfd2 (Always different)
//     IExampleScopedService: bba80089-1157-4041-936d-e96d81dd9d1c (Changes only with lifetime)
//     IExampleSingletonService: a61f1ff4-0b14-4508-bd41-21d852484a7b (Always the same)

Az alkalmazás kimenetében a következő látható:

  • Transient szolgáltatások mindig eltérőek, a szolgáltatás minden lekérésével létrejön egy új példány.
  • Scoped a szolgáltatások csak új hatókörrel változnak, de egy hatókörön belül ugyanazok a példányok.
  • Singleton szolgáltatások mindig ugyanazok, egy új példány csak egyszer jön létre.

Lásd még