Megosztás a következőn keresztül:


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:

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 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. Be kell jelenteni, public hogy az elérhető legyen a fogyasztók számára. Ellentétben más, deklarált internal sealedszolgá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 ServiceCollectionkövetkező helyen:
    • A IConsole implementálási gyár túlterhelése egy "true" értékre IsEnabled beállított típust ad visszaDefaultConsole.
    • A IGreetingService rendszer hozzá van adva egy megfelelő implementációs típussal DefaultGreetingService .
    • Ez FarewellService betontípusként van hozzáadva.
  • Hozza létre a ServiceProvider következőből: ServiceCollection.
  • Oldja fel a szolgáltatásokat és FarewellService a IGreetingService szolgáltatásokat.
  • A feloldott szolgáltatások használatával köszönthet és búcsúzhat egy elnevezett Davidszemé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 ServiceCollectionszolgá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.

Lásd még