Registrace služby

Tento článek popisuje registraci skupin služeb a služeb poskytovaných frameworkem. Poskytuje také podrobnosti o metodách rozšíření registrace služby, které poskytuje .NET.

Registrace skupin služeb prostřednictvím rozšiřovacích metod

.NET používá konvenci pro registraci skupiny souvisejících služeb. Konvence spočívá v použití jedné Add{GROUP_NAME} rozšiřující metody k registraci všech služeb vyžadovaných funkcí architektury. Například AddOptions metoda rozšíření zaregistruje všechny služby potřebné pro použití možností.

Služby poskytované frameworkem

Pokud používáte některý z dostupných vzorů hostitele nebo tvůrce aplikací, použijí se výchozí hodnoty a rozhraní zaregistruje služby. Představte si některé z nejoblíbenějších vzorů pro hostitele a tvůrce aplikací:

Po vytvoření builderu z některého z těchto rozhraní API IServiceCollection má služby definované frameworkem, v závislosti na tom, jak jste hostitele nakonfigurovali. Pro aplikace založené na šablonách .NET by architektura mohla zaregistrovat stovky služeb.

Následující tabulka uvádí malou ukázku těchto služeb registrovaných rámcem.

Typ služby Životnost
Microsoft.Extensions.DependencyInjection.IServiceScopeFactory Singleton
IHostApplicationLifetime Singleton
Microsoft.Extensions.Logging.ILogger<TCategoryName> Singleton
Microsoft.Extensions.Logging.ILoggerFactory Singleton
Microsoft.Extensions.ObjectPool.ObjectPoolProvider Singleton
Microsoft.Extensions.Options.IConfigureOptions<TOptions> Transient
Microsoft.Extensions.Options.IOptions<TOptions> Singleton
System.Diagnostics.DiagnosticListener Singleton
System.Diagnostics.DiagnosticSource Singleton

Metody registrace

Architektura poskytuje metody rozšíření registrace služeb, které jsou užitečné v konkrétních scénářích:

Metoda Automatické odstranění objektů Více implementací Předávání args
Add{LIFETIME}<{SERVICE}, {IMPLEMENTATION}>()

Příklad:

services.AddSingleton<IMyDep, MyDep>();
Ano Ano Ne
Add{LIFETIME}<{SERVICE}>(sp => new {IMPLEMENTATION})

Examples:

services.AddSingleton<IMyDep>(sp => new MyDep());
services.AddSingleton<IMyDep>(sp => new MyDep(99));
Ano Ano Ano
Add{LIFETIME}<{IMPLEMENTATION}>()

Příklad:

services.AddSingleton<MyDep>();
Ano Ne Ne
AddSingleton<{SERVICE}>(new {IMPLEMENTATION})

Examples:

services.AddSingleton<IMyDep>(new MyDep());
services.AddSingleton<IMyDep>(new MyDep(99));
Ne Ano Ano
AddSingleton(new {IMPLEMENTATION})

Examples:

services.AddSingleton(new MyDep());
services.AddSingleton(new MyDep(99));
Ne Ne Ano

Další informace o likvidaci typu najdete v tématu Likvidace služeb.

Registrace služby pouze s typem implementace je ekvivalentní registraci této služby se stejným typem implementace a služby. Představte si například následující kód:

services.AddSingleton<ExampleService>();

Toto je ekvivalentní registraci služby spolu s její implementací stejného typu.

services.AddSingleton<ExampleService, ExampleService>();

Tato ekvivalence je důvod, proč není možné zaregistrovat více implementací služby pomocí metod, které nepoužívají explicitní typ služby. Tyto metody mohou zaregistrovat více instancí služby , ale všechny mají typ implementace stejný.

Libovolnou metodu registrace služby lze použít k registraci více instancí služby stejného typu služby. V následujícím příkladu je AddSingleton dvakrát voláno jako typ služby IMessageWriter. Druhé volání AddSingleton nahrazuje předchozí volání, když je vyřešeno jako IMessageWriter, a přidává k předchozímu volání, když jsou prostřednictvím IEnumerable<IMessageWriter> vyřešeny více služeb. Služby se zobrazují v pořadí, v jakém byly zaregistrovány při řešení prostřednictvím IEnumerable<{SERVICE}>.

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

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddSingleton<IMessageWriter, ConsoleMessageWriter>();
builder.Services.AddSingleton<IMessageWriter, LoggingMessageWriter>();
builder.Services.AddSingleton<ExampleService>();

using IHost host = builder.Build();

_ = host.Services.GetService<ExampleService>();

await host.RunAsync();

Předchozí vzorový zdrojový kód registruje dvě implementace IMessageWriter.

using System.Diagnostics;

namespace ConsoleDI.IEnumerableExample;

public sealed class ExampleService
{
    public ExampleService(
        IMessageWriter messageWriter,
        IEnumerable<IMessageWriter> messageWriters)
    {
        Trace.Assert(messageWriter is LoggingMessageWriter);

        var dependencyArray = messageWriters.ToArray();
        Trace.Assert(dependencyArray[0] is ConsoleMessageWriter);
        Trace.Assert(dependencyArray[1] is LoggingMessageWriter);
    }
}

Definuje ExampleService dva parametry konstruktoru: jeden IMessageWriter a IEnumerable<IMessageWriter>. Jedinou IMessageWriter implementací je poslední registrace, zatímco IEnumerable<IMessageWriter> představuje všechny registrované implementace.

Architektura také poskytuje TryAdd{LIFETIME} rozšiřující metody, které zaregistrují službu pouze v případě, že ještě není zaregistrovaná implementace.

V následujícím příkladu volání AddSingleton registruje ConsoleMessageWriter jako implementaci pro IMessageWriter. Volání TryAddSingleton nemá žádný účinek, protože IMessageWriter již má zaregistrovanou implementaci:

services.AddSingleton<IMessageWriter, ConsoleMessageWriter>();
services.TryAddSingleton<IMessageWriter, LoggingMessageWriter>();

Nemá TryAddSingleton žádný vliv, protože už byl přidán a pokus selže. Tento ExampleService výraz potvrzuje následující:

public class ExampleService
{
    public ExampleService(
        IMessageWriter messageWriter,
        IEnumerable<IMessageWriter> messageWriters)
    {
        Trace.Assert(messageWriter is ConsoleMessageWriter);
        Trace.Assert(messageWriters.Single() is ConsoleMessageWriter);
    }
}

Další informace najdete tady:

Metody TryAddEnumerable(ServiceDescriptor) registrují službu pouze v případě, že ještě neexistuje implementace stejného typu. Více služeb je řešeno skrze IEnumerable<{SERVICE}>. Při registraci služeb přidejte instanci, pokud ještě nebyl přidán jeden ze stejných typů. Autoři knihoven používají TryAddEnumerable aby zabránili registraci více kopií implementace v kontejneru.

V následujícím příkladu první volání TryAddEnumerable registruje MessageWriter jako implementaci pro IMessageWriter1. Druhý hovor zaregistruje MessageWriter pro IMessageWriter2. Třetí volání nemá žádný účinek, protože IMessageWriter1 již má zaregistrovanou implementaci MessageWriter:

public interface IMessageWriter1 { }
public interface IMessageWriter2 { }

public class MessageWriter : IMessageWriter1, IMessageWriter2
{
}

services.TryAddEnumerable(ServiceDescriptor.Singleton<IMessageWriter1, MessageWriter>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMessageWriter2, MessageWriter>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMessageWriter1, MessageWriter>());

Registrace služby je nezávislá na objednávce s výjimkou registrace více implementací stejného typu.

IServiceCollection je kolekce ServiceDescriptor objektů. Následující příklad ukazuje, jak zaregistrovat službu vytvořením a přidáním ServiceDescriptor:

string secretKey = Configuration["SecretKey"];
var descriptor = new ServiceDescriptor(
    typeof(IMessageWriter),
    _ => new DefaultMessageWriter(secretKey),
    ServiceLifetime.Transient);

services.Add(descriptor);

Integrované Add{LIFETIME} metody používají stejný přístup. Podívejte se například na zdrojový kód AddScoped.