如何使用 ASP.NET 核心依赖注入来应用装饰器

How to apply decorators with ASP.NET Core Dependency Injection

在 ASP.NET MVC 5 应用程序上,我有以下 StructureMap 配置:

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

有谁知道如何使用 ASP.NET 核心 IOC 进行此配置?

开箱即用的 IoC 容器不支持修饰模式或自动发现,据我所知 "by design"。

我们的想法是提供一个开箱即用的基本 IoC 结构,或者可以插入其他 IoC 容器以扩展默认功能。

因此,如果您需要任何高级功能(支持特定构造函数、自动注册实现接口或注入装饰器和拦截器的所有类型),您必须自己编写或使用提供此功能的 IoC 容器功能。

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 包正在开发中。

在我的blogpost中我描述了一个相对简单的扩展方法如何轻松解决这个问题。这是 post 中的一个示例,它显示了装饰器配置的样子:

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

使用 Scrutor. Just install the nuget 包,然后执行以下操作。

services.AddSingleton<IGreeter, Greeter>();
services.Decorate<IGreeter, GreeterLogger>();
services.Decorate<IGreeter, GreeterExceptionHandler>();

顺序很重要。上面GreeterLogger装饰了Greeter。 GreeterExceptionHandler 装饰 GreeterLogger.

如果您需要更多信息,请查看 this and this

当然,您也可以使用流行的 Autofac

如果您想了解如何配置 Autofac,请查看 Ardalis Clean Arch template

另一个例子

services.AddTransient<Greeter>();
services.AddTransient<IGreeter>(g=>
   ActivatorUtilities.CreateInstance<GreeterLogger>(g,g.GetRequiredServices<Greeter>())
);

或通用

private static void AddTransientDecorated<TInterface,TService,TDecorator>(this IServiceCollection services)
{
    services.AddTransient(typeof(TService));
    services.AddTransient(typeof(TInterface), p => ActivatorUtilities.CreateInstance<TDecorator>(p, p.GetRequiredService<TService>()));
}

补充信息