Kommentar
Å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.
I den här snabbstarten skapar du en .NET-konsolapp som manuellt skapar en ServiceCollection och motsvarande ServiceProvider. Du lär dig hur du registrerar tjänster och löser dem med hjälp av beroendeinmatning (DI). Den här artikeln använder NuGet-paketet Microsoft.Extensions.DependencyInjection för att demonstrera grunderna i DI i .NET.
Anmärkning
Den här artikeln drar inte nytta av de allmänna värdfunktionerna . En mer omfattande guide finns i Använda beroendeinmatning i .NET.
Get started
Kom igång genom att skapa ett nytt .NET-konsolprogram med namnet DI.Basics. I Visual Studio väljer du Arkiv > Nytt > projekt eller använder .NET CLI och anger dotnet new console.
Lägg sedan till en paketreferens till Microsoft.Extensions.DependencyInjection i projektfilen. När du har lagt till paketet kontrollerar du att projektet liknar följande XML för FILEN 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.5" />
</ItemGroup>
</Project>
Grunderna för beroendeinjektion
Beroendeinmatning är ett designmönster som du kan använda för att ta bort hårdkodade beroenden och göra programmet mer underhållsbart och testbart. DI är en teknik för att uppnå inversion av kontroll (IoC) mellan klasser och deras beroenden.
NuGet-paketet Microsoft.Extensions.DependencyInjection.Abstractions definierar abstraktionerna för DI i .NET:
- IServiceCollection: Definierar ett kontrakt för en samling tjänstbeskrivningar.
- IServiceProvider: Definierar en mekanism för att hämta ett tjänstobjekt.
- ServiceDescriptor: Beskriver en tjänst med dess tjänsttyp, implementering och livslängd.
I .NET hanterar du DI genom att lägga till tjänster och konfigurera dem i en IServiceCollection. När du har registrerat tjänsterna, anropar du metoden BuildServiceProvider för att bygga en IServiceProvider instans. Fungerar IServiceProvider som en container för alla registrerade tjänster och du använder den för att lösa tjänster.
Skapa exempeltjänster
Alla tjänster skapas inte lika. Vissa tjänster kräver en ny instans varje gång tjänstcontainern hämtar dem (övergående), medan andra ska delas mellan olika begäranden (begränsad) eller under hela appens livslängd (singleton). Mer information om tjänstlivslängder finns i Tjänstlivslängder.
På samma sätt exponerar vissa tjänster bara en konkret typ, medan andra uttrycks som ett kontrakt mellan ett gränssnitt och en implementeringstyp. Du skapar flera varianter av tjänster för att demonstrera dessa begrepp.
Skapa en ny C#-fil med namnet IConsole.cs och lägg till följande kod:
public interface IConsole
{
void WriteLine(string message);
}
Den här filen definierar ett IConsole gränssnitt som exponerar en enda metod, WriteLine. Skapa sedan en ny C#-fil med namnet DefaultConsole.cs och lägg till följande kod:
internal sealed class DefaultConsole : IConsole
{
public bool IsEnabled { get; set; } = true;
void IConsole.WriteLine(string message)
{
if (IsEnabled is false)
{
return;
}
Console.WriteLine(message);
}
}
Föregående kod representerar standardimplementeringen av IConsole gränssnittet. Metoden WriteLine skriver villkorligt till konsolen baserat på IsEnabled egenskapen .
Tips/Råd
Namngivning av en implementering är ett val som utvecklingsteamet bör komma överens om. Prefixet Default är en vanlig konvention som anger en standardimplementering av ett gränssnitt, men det krävs inte.
Skapa sedan en IGreetingService.cs-fil och lägg till följande C#-kod:
public interface IGreetingService
{
string Greet(string name);
}
Lägg sedan till en ny C#-fil med namnet DefaultGreetingService.cs och lägg till följande kod:
internal sealed class DefaultGreetingService(
IConsole console) : IGreetingService
{
public string Greet(string name)
{
var greeting = $"Hello, {name}!";
console.WriteLine(greeting);
return greeting;
}
}
Föregående kod representerar standardimplementeringen av IGreetingService gränssnittet. Tjänstimplementeringen kräver en IConsole som primär konstruktorparameter.
Greet-metoden:
- Skapar en
greetinggivetname. - Anropar
WriteLine-metoden påIConsole-instansen. - Returnerar
greetingtill anroparen.
Klassen DefaultGreetingService visar att du kan seal tjänsteimplementationer för att förhindra arv och använd internal för att begränsa åtkomsten till sammansättningen.
Den sista tjänsten som ska skapas är filen FarewellService.cs . Lägg till följande C#-kod innan du fortsätter:
public class FarewellService(IConsole console)
{
public string SayGoodbye(string name)
{
var farewell = $"Goodbye, {name}!";
console.WriteLine(farewell);
return farewell;
}
}
Representerar FarewellService en konkret typ, inte ett gränssnitt. Du bör deklarera det för public att göra det tillgängligt för konsumenter. Till skillnad från andra tjänstimplementeringstyper som du deklarerar som internal och sealedvisar den här koden att inte alla tjänster behöver vara gränssnitt.
Program Uppdatera klassen
Öppna filen Program.cs och ersätt den befintliga koden med följande C#-kod:
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");
Föregående kod visar hur du:
- Skapa en ny
ServiceCollectioninstans. - Registrera och konfigurera tjänster i
ServiceCollection:- Tjänsten
IConsolegenom att använda överbelastning av implementationsfabriken. Returnera enDefaultConsole-typ medIsEnabledegenskapen inställd påtrue. - Tjänsten
IGreetingServicemed en motsvarande implementeringstyp avDefaultGreetingService. - Tjänsten
FarewellServicesom en konkret typ.
- Tjänsten
- Bygg
ServiceProviderfrånServiceCollection. - Lös tjänsterna
IGreetingServiceochFarewellService. - Använd de lösta tjänsterna för att hälsa och säga adjö till en person med namnet
David.
Om du uppdaterar IsEnabled-egenskapen för DefaultConsole till false kommer Greet- och SayGoodbye-metoderna att utelämna att skriva de resulterande meddelandena till konsolen. Den här ändringen visar att IConsole tjänsten matas in i IGreetingService tjänsterna och FarewellService som ett beroende som påverkar appens beteende.
Alla dessa tjänster är registrerade som singletons. För det här exemplet fungerar det identiskt om du registrerar dem som tillfälliga eller begränsade tjänster.
Viktigt!
I det här invecklade exemplet spelar tjänstlivslängden ingen roll. I ett verkligt program bör du noga överväga livslängden för varje tjänst.
Kör exempelappen
Om du vill köra exempelappen trycker du antingen på F5 i Visual Studio eller Visual Studio Code eller kör dotnet run kommandot i terminalen. När appen är klar visas följande utdata:
Hello, David!
Goodbye, David!
Tjänstbeskrivningar
De vanligaste API:erna för att lägga till tjänster i ServiceCollection är generiska utökande metoder namngivna baserat på livstid, till exempel:
AddSingleton<TService>AddTransient<TService>AddScoped<TService>
Dessa metoder är bekvämlighetsmetoder som skapar en ServiceDescriptor instans och lägger till den i ServiceCollection.
ServiceDescriptor är en enkel klass som beskriver en tjänst med dess tjänsttyp, implementeringstyp och livslängd. Den kan också beskriva implementeringsfabriker och instanser.
För varje tjänst som du registrerade i ServiceCollection, kan du i stället anropa Add metoden med en ServiceDescriptor instans direkt. Tänk på följande exempel:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IConsole),
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
},
lifetime: ServiceLifetime.Singleton));
Föregående kod motsvarar hur IConsole tjänsten registrerades i ServiceCollection. Metoden Add lägger till en ServiceDescriptor instans som beskriver IConsole tjänsten. Den statiska metoden ServiceDescriptor.Describe delegerar till olika ServiceDescriptor konstruktorer. Överväg motsvarande kod för IGreetingService tjänsten:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IGreetingService),
implementationType: typeof(DefaultGreetingService),
lifetime: ServiceLifetime.Singleton));
Föregående kod beskriver tjänsten IGreetingService med dess tjänsttyp, implementeringstyp och livslängd. Tänk slutligen på motsvarande kod för FarewellService tjänsten:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(FarewellService),
implementationType: typeof(FarewellService),
lifetime: ServiceLifetime.Singleton));
Föregående kod beskriver den konkreta FarewellService typen som både tjänst- och implementeringstyper. Tjänsten är registrerad som en singleton-tjänst.