CQRS 命令/查询装饰器
Posted
技术标签:
【中文标题】CQRS 命令/查询装饰器【英文标题】:CQRS Commands/Queries decorators 【发布时间】:2021-12-19 10:12:51 【问题描述】:如何为IQueryHandler
和ICommandHandler
添加自定义装饰器?
我正在尝试使用 Autofac 和 MediatR 库在简单的控制台应用程序中实现 CQRS 模式。
该项目具有以下结构:
我想以这种方式处理命令和查询:
请求处理程序装饰器应用 命令/查询处理程序装饰器应用 命令/查询处理程序做某事 命令/查询处理程序装饰器完成 请求处理程序装饰器完成主文件:
internal class Program
static async Task Main(string[] args)
var container = ConfigureCQRS();
using var scope = container.BeginLifetimeScope();
var mediatr = scope.Resolve<IMediator>();
await mediatr.Send(new MyCommand("Command1"));
await mediatr.Send(new MyQuery("Query1"));
private static IContainer ConfigureCQRS()
var builder = new ContainerBuilder();
builder.RegisterModule(new MediatRModule(typeof(Program).Assembly));
builder.RegisterGenericDecorator(typeof(LoggingRequestHandlerDecorator<,>), typeof(IRequestHandler<,>));
builder.RegisterGenericDecorator(typeof(UnitOfWorkCommandHandlerDecorator<,>), typeof(ICommandHandler<,>));
builder.RegisterGenericDecorator(typeof(DiagnosticQueryHandlerDecorator<,>), typeof(IQueryHandler<,>));
return builder.Build();
MediatRModule.cs:
internal class MediatRModule : Autofac.Module
private readonly Assembly[] assemblies;
internal MediatRModule(params Assembly[] assemblies)
this.assemblies = assemblies;
protected override void Load(ContainerBuilder builder)
builder.RegisterMediatR(assemblies);
var openHandlerTypes = new[]
typeof(IRequestHandler<,>),
typeof(IRequestExceptionHandler<,,>),
typeof(IRequestExceptionAction<,>),
typeof(INotificationHandler<>),
;
foreach (var openHandlerType in openHandlerTypes)
builder.RegisterAssemblyTypes(this.assemblies)
.AsClosedTypesOf(openHandlerType)
.AsImplementedInterfaces();
builder.RegisterGeneric(typeof(RequestPostProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(RequestPreProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(RequestExceptionActionProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(RequestExceptionProcessorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.Register<ServiceFactory>(outerContext =>
var innerContext = outerContext.Resolve<IComponentContext>();
return serviceType => innerContext.Resolve(serviceType);
)
.InstancePerLifetimeScope();
带有装饰器的典型命令:
internal record MyCommand(string Text) : CommandBase<string>;
internal class MyCommandHandler : ICommandHandler<MyCommand, string>
public Task<string> Handle(MyCommand command, CancellationToken cancellationToken)
Console.WriteLine($"Command result: command.Text");
return Task.FromResult(command.Text);
典型的请求处理程序装饰器:
internal class LoggingRequestHandlerDecorator<TRequest, TResult> :
IRequestHandler<TRequest, TResult>
where TRequest : IRequest<TResult>
private readonly IRequestHandler<TRequest, TResult> _decorated;
public LoggingRequestHandlerDecorator(IRequestHandler<TRequest, TResult> decorated)
this._decorated = decorated;
public async Task<TResult> Handle(TRequest request, CancellationToken cancellationToken)
Console.WriteLine("LoggingRequestHandlerDecorator start");
var result = await _decorated.Handle(request, cancellationToken);
Console.WriteLine("LoggingRequestHandlerDecorator end");
return result;
典型的命令处理程序装饰器:
internal class UnitOfWorkCommandHandlerDecorator<TCommand, TResult> :
ICommandHandler<TCommand, TResult>
where TCommand : ICommand<TResult>
private readonly ICommandHandler<TCommand, TResult> _decorated;
public UnitOfWorkCommandHandlerDecorator(ICommandHandler<TCommand, TResult> decorated)
_decorated = decorated;
public async Task<TResult> Handle(TCommand command, CancellationToken cancellationToken)
Console.WriteLine("UnitOfWorkCommandHandlerDecorator start");
var result = await _decorated.Handle(command, cancellationToken);
Console.WriteLine("UnitOfWorkCommandHandlerDecorator end");
return result;
完整项目发布在github上:github.com/LeftTwixWand/CommandQueryDecorators
【问题讨论】:
【参考方案1】:好的,我已经解决了这个问题。 只需要在装饰器的构造函数中接受 IRequestHandler 即可。
【讨论】:
对于这些用例,您还可以使用行为,请参阅github.com/jbogard/MediatR/wiki/Behaviors @GeorgMüller 感谢您的评论!我知道管道,但我在某些情况下需要使用装饰器,例如,测量查询速度,并且看起来,装饰器是正确的决定。以上是关于CQRS 命令/查询装饰器的主要内容,如果未能解决你的问题,请参考以下文章