Keyed services, фабрики, декораторы, IServiceScopeFactory

↑ 3.2 Dependency Injection · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Показывает, что вы умеете выходить за рамки «один интерфейс — одна реализация».

Объяснение

Keyed services (.NET 8)

builder.Services.AddKeyedSingleton<INotifier, EmailNotifier>("email");
builder.Services.AddKeyedSingleton<INotifier, SmsNotifier>("sms");
 
public class Alerts([FromKeyedServices("sms")] INotifier notifier) { }
var email = provider.GetRequiredKeyedService<INotifier>("email");

Фабрики

builder.Services.AddScoped<IPricing>(sp =>
{
    var opts = sp.GetRequiredService<IOptions<PricingOptions>>().Value;
    return opts.UseNew ? sp.GetRequiredService<NewPricing>() : sp.GetRequiredService<OldPricing>();
});

Фабрика нужна, когда реализация выбирается в рантайме или требует параметров, которых нет в контейнере (Func<T>-фабрики или ActivatorUtilities.CreateInstance).

Декораторы

Встроенный контейнер не поддерживает их напрямую; используют Scrutor или ручную регистрацию:

builder.Services.AddScoped<OrderService>();
builder.Services.AddScoped<IOrderService>(sp =>
    new LoggingOrderService(sp.GetRequiredService<OrderService>(), sp.GetRequiredService<ILogger<LoggingOrderService>>()));
 
// Scrutor
builder.Services.Decorate<IOrderService, CachingOrderService>();

IServiceScopeFactory

Создаёт scope вне HTTP-запроса — для фоновых задач, обработчиков сообщений и singleton-ов (см. Captive dependency и другие ловушки DI).

Нюансы и подводные камни

  • Декоратор с неверным порядком регистрации зациклится на себе.
  • Ключи в Keyed Services — object: используйте константы/enum, а не «магические» строки.
  • GetService возвращает null, GetRequiredService бросает: предпочитайте второй.
  • Регистрация одной реализации под несколькими интерфейсами: singleton нужно зарегистрировать сам и делегировать интерфейсы, иначе экземпляров будет несколько.

Практика

  1. Реализуйте выбор канала уведомления по ключу.
  2. Добавьте кэширующий декоратор к сервису через Scrutor.
  3. Создайте scope в обработчике очереди.

Вопросы с ответами

Связанные темы