Keyed services, фабрики, декораторы, IServiceScopeFactory
↑ 3.2 Dependency Injection · ← Предыдущая · → Следующая
Зачем это на собесе
Показывает, что вы умеете выходить за рамки «один интерфейс — одна реализация».
Объяснение
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 нужно зарегистрировать сам и делегировать интерфейсы, иначе экземпляров будет несколько.
Практика
- Реализуйте выбор канала уведомления по ключу.
- Добавьте кэширующий декоратор к сервису через Scrutor.
- Создайте scope в обработчике очереди.
Вопросы с ответами
Для чего нужны keyed services?
Для регистрации нескольких реализаций одного интерфейса и выбора нужной по ключу без своих фабрик.
Как реализовать декоратор при встроенном контейнере?
Ручной регистрацией через фабрику либо библиотекой Scrutor (
Decorate).
Когда нужен IServiceScopeFactory?
Когда код работает вне HTTP-запроса или в singleton и должен получать scoped-сервисы.