Sdílet prostřednictvím


Rychlý start: Základy injektáže závislostí v .NET

V tomto rychlém startu vytvoříte konzolovou aplikaci .NET, která ručně vytvoří ServiceCollection a odpovídající ServiceProvider. Naučíte se registrovat služby a řešit je pomocí injektáže závislostí (DI). Tento článek používá balíček NuGet Microsoft.Extensions.DependencyInjection k předvedení základů DI v .NET.

Poznámka:

Tento článek nevyužívá obecné funkce hostitele . Podrobnější průvodce najdete v tématu Použití injektáže závislostí v .NET.

Začínáme

Začněte vytvořením nové konzolové aplikace .NET s názvem DI.Basics. Na některé z nejběžnějších přístupů k vytvoření projektu konzoly se odkazuje v následujícím seznamu:

Do souboru projektu je potřeba přidat odkaz na balíček Microsoft.Extensions.DependencyInjection . Bez ohledu na přístup se ujistěte, že se projekt podobá následujícímu kódu XML souboru DI.Basics.csproj :

<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>

Základy injektování závislostí

Injektáž závislostí je vzor návrhu, který umožňuje odebrat pevně zakódované závislosti a zajistit, aby byla vaše aplikace lépe udržovatelná a testovatelná. DI je technika pro dosažení inverze řízení (IoC) mezi třídami a jejich závislostmi.

Abstrakce pro DI v .NET jsou definovány v NuGet balíčku Microsoft.Extensions.DependencyInjection.Abstractions:

V .NET se di spravuje přidáním služeb a jejich konfigurací v objektu IServiceCollection. Po registraci IServiceProvider služeb je instance vytvořena voláním BuildServiceProvider metody. Funguje IServiceProvider jako kontejner všech registrovaných služeb a slouží k řešení služeb.

Vytvoření ukázkových služeb

Ne všechny služby se vytvářejí stejně. Některé služby vyžadují novou instanci pokaždé, když je kontejner služby získá (přechodné), zatímco jiné by měly být sdíleny napříč požadavky (s omezeným rozsahem) nebo po celou dobu životnosti aplikace (singleton). Další informace o životnostech služeb najdete v tématu Životnost služby.

Podobně některé služby zpřístupňují pouze konkrétní typ, zatímco jiné jsou vyjádřeny jako kontrakt mezi rozhraním a typem implementace. Vytvoříte několik variant služeb, které vám pomůžou tyto koncepty předvést.

Vytvořte nový soubor C# s názvem IConsole.cs a přidejte následující kód:

public interface IConsole
{
    void WriteLine(string message);
}

Tento soubor definuje IConsole rozhraní, které zveřejňuje jednu metodu , WriteLine. Dále vytvořte nový soubor jazyka C# s názvem DefaultConsole.cs a přidejte následující kód:

internal sealed class DefaultConsole : IConsole
{
    public bool IsEnabled { get; set; } = true;

    void IConsole.WriteLine(string message)
    {
        if (IsEnabled is false)
        {
            return;
        }

        Console.WriteLine(message);
    }
}

Předchozí kód představuje výchozí implementaci IConsole rozhraní. Metoda WriteLine podmíněně zapisuje do konzole na základě vlastnosti IsEnabled.

Návod

Pojmenování implementace je volba, na které by se měl váš vývojový tým shodnout. Předpona Default je běžnou konvencí označující výchozí implementaci rozhraní, ale nevyžaduje se.

Dále vytvořte soubor IGreetingService.cs a přidejte následující kód jazyka C#:

public interface IGreetingService
{
    string Greet(string name);
}

Pak přidejte nový soubor C# s názvem DefaultGreetingService.cs a přidejte následující kód:

internal sealed class DefaultGreetingService(
    IConsole console) : IGreetingService
{
    public string Greet(string name)
    {
        var greeting = $"Hello, {name}!";

        console.WriteLine(greeting);

        return greeting;
    }
}

Předchozí kód představuje výchozí implementaci IGreetingService rozhraní. Implementace služby vyžaduje IConsole jako primární parametr konstruktoru. Metoda Greet:

  • Vytvoří greeting na základě name.
  • Volá metodu WriteLine na instanci IConsole.
  • Vrátí greeting volajícímu.

Poslední službou, která se má vytvořit, je soubor FarewellService.cs a před pokračováním přidejte následující kód jazyka C#:

public class FarewellService(IConsole console)
{
    public string SayGoodbye(string name)
    {
        var farewell = $"Goodbye, {name}!";

        console.WriteLine(farewell);

        return farewell;
    }
}

Představuje FarewellService konkrétní typ, nikoli rozhraní. Měla by být deklarována tak public , aby byla přístupná uživatelům. Na rozdíl od jiných typů implementace služby, které byly deklarovány jako internal a sealed, tento kód ukazuje, že ne všechny služby musí být rozhraní. Ukazuje také, že implementace služeb mohou sealed zabránit dědičnosti a internal omezit přístup k sestavě.

Aktualizujte třídu Program

Otevřete soubor Program.cs a nahraďte stávající kód následujícím kódem jazyka C#:

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");

Předchozí aktualizovaný kód ukazuje postupy:

  • Vytvořte novou ServiceCollection instanci.
  • Registrace a konfigurace služeb v ServiceCollection:
    • Pomocí přetížení implementační továrny IConsole se vrátí typ DefaultConsole s IsEnabled nastaveným na true.
    • IGreetingService je přidán s odpovídajícím typem implementace DefaultGreetingService.
    • Je FarewellService přidán jako konkrétní typ.
  • Sestavte ServiceProvider z ServiceCollection.
  • Vyřešte služby IGreetingService a FarewellService.
  • Pomocí vyřešených služeb pozdravte a rozlučte se s osobou jménem David.

Pokud aktualizujete IsEnabled vlastnost DefaultConsole na false, Greet a SayGoodbye metody vynechají zápis zpráv do konzoly. Taková změna pomáhá demonstrovat, že je IConsole služba injektována do IGreetingService a FarewellService služeb jako závislost, která ovlivňuje chování aplikace.

Všechny tyto služby jsou zaregistrované jako singletony, i když pro tuto ukázku fungují stejně, pokud byly zaregistrovány jako přechodné nebo omezené služby.

Důležité

V tomto nepochybovaném příkladu nezáleží na životnosti služby, ale v reálné aplikaci byste měli pečlivě zvážit životnost každé služby.

Spuštění ukázkové aplikace

Ukázkovou aplikaci spustíte stisknutím klávesy F5 v sadě Visual Studio nebo editoru Visual Studio Code nebo spuštěním dotnet run příkazu v terminálu. Po dokončení aplikace by se měl zobrazit následující výstup:

Hello, David!
Goodbye, David!

Popisovače služeb

Nejčastěji používaná rozhraní API pro přidávání služeb do ServiceCollection jsou obecné metody s názvy životního cyklu, jako například:

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

Tyto metody jsou usnadňující, které vytvářejí instanci ServiceDescriptor a přidávají ji do ServiceCollection. Jedná se ServiceDescriptor o jednoduchou třídu, která popisuje službu s jejím typem služby, typem implementace a životností. Může také popsat implementační továrny a instance.

Pro každou službu, kterou jste zaregistrovali v nástroji ServiceCollection, můžete místo toho přímo volat metodu Add s instancí ServiceDescriptor. Zvažte následující příklady:

services.Add(ServiceDescriptor.Describe(
    serviceType: typeof(IConsole),
    implementationFactory: static _ => new DefaultConsole
    {
        IsEnabled = true
    },
    lifetime: ServiceLifetime.Singleton));

Předchozí kód je ekvivalentní způsobu, jakým byla služba IConsole zaregistrována v ServiceCollection souboru. Metoda Add se používá k přidání ServiceDescriptor instance, která popisuje IConsole službu. Statická metoda ServiceDescriptor.Describe deleguje na různé ServiceDescriptor konstruktory. Vezměte v úvahu ekvivalentní kód pro IGreetingService službu:

services.Add(ServiceDescriptor.Describe(
    serviceType: typeof(IGreetingService),
    implementationType: typeof(DefaultGreetingService),
    lifetime: ServiceLifetime.Singleton));

Předchozí kód popisuje IGreetingService službu s jejím typem služby, typem implementace a životností. Nakonec zvažte ekvivalentní kód pro FarewellService službu:

services.Add(ServiceDescriptor.Describe(
    serviceType: typeof(FarewellService),
    implementationType: typeof(FarewellService),
    lifetime: ServiceLifetime.Singleton));

Předchozí kód popisuje konkrétní FarewellService typ jako typ služby i implementace. Služba je zaregistrovaná jako jednoúčelová služba.

Viz také