如何使用 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.
当然,您也可以使用流行的 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>()));
}
补充信息
在 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.
当然,您也可以使用流行的 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>()));
}
补充信息