Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här självstudien visar hur du använder dependency injection (DI) i .NET. Med Microsoft Extensionshanteras DI genom att lägga till tjänster och konfigurera dem i en IServiceCollection. Gränssnittet IHost exponerar IServiceProvider-instansen, som fungerar som en container för alla registrerade tjänster.
I den här handledningen lär du dig att:
- Skapa en .NET-konsolapp som använder beroendeinmatning
- Skapa och konfigurera en allmän värd
- Skriva flera gränssnitt och motsvarande implementeringar
- Använda tjänstens livslängd och omfattning för DI
Förutsättningar
- .NET Core 3.1 SDK eller senare.
- Kunskaper om att skapa nya .NET-program och installera NuGet-paket.
Skapa ett nytt konsolprogram
Använd antingen kommandot dotnet new eller en ny IDE-projektguide och skapa ett nytt .NET-konsolprogram med namnet ConsoleDI.Example. Lägg till Microsoft.Extensions.Hosting NuGet-paketet i projektet.
Den nya konsolappens projektfil bör likna följande:
<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.Configuration.Binder" Version="9.0.10" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
  </ItemGroup>
</Project>
Viktig
I det här exemplet krävs Microsoft.Extensions.Hosting NuGet-paketet för att skapa och köra appen. Vissa metapaket kan innehålla Microsoft.Extensions.Hosting-paketet, i vilket fall en explicit paketreferens inte krävs.
Lägga till gränssnitt
I den här exempelappen får du lära dig hur beroendeinmatning hanterar tjänstens livslängd. Du skapar flera gränssnitt som representerar olika tjänstlivslängder. Lägg till följande gränssnitt i projektrotkatalogen:
IReportServiceLifetime.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IReportServiceLifetime
{
    Guid Id { get; }
    ServiceLifetime Lifetime { get; }
}
Gränssnittet IReportServiceLifetime definierar:
- En Guid Idegenskap som representerar tjänstens unika identifierare.
- En ServiceLifetime egenskap som representerar tjänstens livslängd.
IExampleTransientService.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IExampleTransientService : IReportServiceLifetime
{
    ServiceLifetime IReportServiceLifetime.Lifetime => ServiceLifetime.Transient;
}
IExampleScopedService.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IExampleScopedService : IReportServiceLifetime
{
    ServiceLifetime IReportServiceLifetime.Lifetime => ServiceLifetime.Scoped;
}
IExampleSingletonService.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IExampleSingletonService : IReportServiceLifetime
{
    ServiceLifetime IReportServiceLifetime.Lifetime => ServiceLifetime.Singleton;
}
Alla undergränssnitt i IReportServiceLifetime implementerar uttryckligen IReportServiceLifetime.Lifetime med en standardimplementering. Till exempel implementerar IExampleTransientService uttryckligen IReportServiceLifetime.Lifetime med värdet ServiceLifetime.Transient.
Lägga till standardimplementeringar
Exempelimplementeringarna initierar alla sina Id-egenskap med resultatet av Guid.NewGuid(). Lägg till följande standardimplementeringsklasser för de olika tjänsterna i projektrotkatalogen:
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();
}
Varje implementering definieras som internal sealed och implementerar motsvarande gränssnitt. De behöver inte vara internal eller sealed, men det är vanligt att behandla implementeringar som internal för att undvika att läcka implementeringstyper till externa konsumenter. Eftersom varje typ inte utökas markeras den dessutom som sealed. Till exempel implementerar ExampleSingletonServiceIExampleSingletonService.
Lägga till en tjänst som kräver DI
Lägg till följande reporterklass för tjänstlivslängd, som fungerar som en tjänst i konsolappen:
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})");
}
              ServiceLifetimeReporter definierar en konstruktor som kräver vart och ett av de ovan nämnda tjänstgränssnitten, dvs. IExampleTransientService, IExampleScopedServiceoch IExampleSingletonService. Objektet exponerar en enda metod som gör att konsumenten kan rapportera om tjänsten med en viss lifetimeDetails parameter. När den anropas loggar ReportServiceLifetimeDetails-metoden varje tjänsts unika identifierare med meddelandet om tjänstens livslängd. Loggmeddelandena hjälper till att visualisera tjänstens livslängd.
Registrera tjänster för DI
Uppdatera Program.cs med följande kod:
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();
}
Varje services.Add{LIFETIME}<{SERVICE}> tilläggsmetod lägger till (och kan konfigurera) tjänster. Vi rekommenderar att appar följer den här konventionen. Placera inte tilläggsmetoder i Microsoft.Extensions.DependencyInjection namnrymd om du inte redigerar ett officiellt Microsoft-paket. Tilläggsmetoder som definieras i Microsoft.Extensions.DependencyInjection namnområde:
- Visas i IntelliSense utan att det krävs fler usingdirektiv.
- Minska antalet obligatoriska using-direktiv i deProgram- ellerStartupklasser där dessa tilläggsmetoder vanligtvis anropas.
Appen:
- Skapar en IHostApplicationBuilder-instans med inställningar för värdbyggare .
- Konfigurerar tjänster och lägger till dem med motsvarande tjänstlivslängd.
- Anropar Build() och tilldelar en instans av IHost.
- Anropar ExemplifyServiceLifetimeoch skickar in IHost.Services.
Slutsats
I den här exempelappen skapade du flera gränssnitt och motsvarande implementeringar. Var och en av dessa tjänster identifieras unikt och paras ihop med en ServiceLifetime. Exempelappen visar hur du registrerar tjänstimplementeringar mot ett gränssnitt och hur du registrerar rena klasser utan stödgränssnitt. Exempelappen visar sedan hur beroenden som definieras som konstruktorparametrar löses vid körning.
När du kör appen visas utdata som liknar följande:
// 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)
Från apputdata kan du se följande:
- Transient tjänster är alltid olika. En ny instans skapas med varje hämtning av tjänsten.
- Scoped tjänster ändras endast med ett nytt omfång, men är samma instans inom ett omfång.
- Singleton tjänster är alltid desamma. En ny instans skapas bara en gång.