Как применять декораторы с ASP.NET Core Dependency Injection

В приложении ASP.NET MVC 5 у меня есть следующая конфигурация StructureMap:

cfg.For(typeof(IRequestHandler<,>)).DecorateAllWith(typeof(MediatorPipeline<,>));

Кто-нибудь знает, как сделать эту конфигурацию с помощью ASP.NET Core IOC?

Ответ 1

Контейнер IoC из коробки не поддерживает оформление шаблона или автоматическое обнаружение, которое, как я знаю, "по дизайну".

Идея состоит в том, чтобы предоставить базовую структуру IoC, которая работает из коробки или где могут быть подключены другие контейнеры IoC, чтобы расширить функциональность по умолчанию.

Итак, если вам нужны какие-либо дополнительные функции (поддержка определенного конструктора, автоматическая регистрация всех типов, которые реализуют интерфейс или инкрустацию декораторов и перехватчиков), вам нужно либо написать его самостоятельно, либо использовать контейнер IoC, который предлагает эту функцию.

Ответ 2

Этот workaround не применяет декоратор ко всем экземплярам типа, но использует методы расширения для абстрагирования логики декоратора в другую файл.

Определение структуры декоратора, например:

public static class QueryHandlerRegistration
{
    public static IServiceCollection RegisterQueryHandler<TQueryHandler, TQuery, TResult>(
        this IServiceCollection services) 
        where TQuery : IQuery<TResult>
        where TQueryHandler : class, IQueryHandler<TQuery, TResult>
    {
        services.AddTransient<TQueryHandler>();
        services.AddTransient<IQueryHandler<TQuery, TResult>>(x =>
            new LoggingDecorator<TQuery, TResult>(x.GetService<ILogger<TQuery>>(), x.GetService<TQueryHandler>()));
        return services;
    }
}

И назовем это так:

services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();

services.RegisterQueryHandler<FindThingByIdQueryHandler, FindThingByIdQuery, Thing>();

Там также работает Scrutor.

Ответ 3

В своем блоге я описал, как относительно простой метод расширения может легко решить эту проблему. Вот пример из этого поста, который показывает, как может выглядеть конфигурация декоратора:

services.AddDecorator<IEmailMessageSender, EmailMessageSenderWithRetryDecorator>(decorateeServices =>
    {
        decorateeServices.AddScoped<IEmailMessageSender, SmtpEmailMessageSender>();
    });