我想装饰一个MediatR Handler。我尝试使用行为,但行为为每个实现IRequestHandler<TRequest,TResponse>
的处理程序注入装饰器
public class ProcessFirstCommand : IRequest<bool>
{
public string Message { get; set; }
}
public class ProcessFirstCommandHandler : IRequestHandler<ProcessFirstCommand, bool>
{
public Task<bool> Handle(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("Inside Process First Command Handler");
return Task.FromResult(true);
}
}
public class Manager
{
private readonly IMediator _mediator;
public Manager(IMediator mediator)
{
_mediator = mediator;
}
public void Execute()
{
_mediator.Send(new ProcessFirstCommand());
}
}
//Registering in Autofac for IRequestHandler
public class Module : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(ThisAssembly)
.AsClosedTypesOf(typeof(IRequestHandler<,>));
}
}
问题:如何在调用ProcessFirstCommandHandler类的Handle方法之前添加将执行的装饰器,而不是其他实现IRequestHandler的类。
当Manager对象执行此行时,如何在ProcessFirstCommandHandler之前首先调用下面的类Handle方法_mediator.Send(new ProcessFirstCommand());
public class ProcessFirstCommandHandlerDecorator<TRequest, TResponse> : IRequestHandler<ProcessFirstCommand, bool>
where TRequest : ProcessFirstCommand
{
private readonly IRequestHandler<ProcessFirstCommand, bool> _handler;
public ProcessFirstCommandHandlerDecorator(IRequestHandler<ProcessFirstCommand, bool> handler)
{
_handler = handler;
}
public Task<bool> Handle(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("Inside Process First Command Handler Decorator");
_handler.Handle(request, cancellationToken);
return Task.FromResult(true);
}
}
如果你想要做的就是在调用处理程序之前运行一些东西,那么你可以利用Behaviors来实现它。我知道你之前说过你已经尝试过这个,但是,你可以创建一个运行IRequestPreProcessor的所有实现的生成行为。
注意:以下过程适用于在处理程序运行之后实现某些内容,您只需将IRequestPreProcessor的实现更改为IReqiestPostProcessor
所以如果你有你的命令处理程序:
public class ProcessFirstCommandHandler : IRequestHandler<ProcessFirstCommand, bool>
{
public Task<bool> Handle(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("Inside Process First Command Handler");
return Task.FromResult(true);
}
}
您可以实现IRequestPreProcessor(您需要的装饰器),但一定要指定您希望它运行的命令
public class PreProcessFirstCommand : IRequestPreprocessor<ProcessFirstCommand>
{
public ProcessFirstCommandHandlerDecorator()
{
}
public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("Inside Process First Command Handler Decorator");
}
}
这将由您的通用PreProcessorBehavi激活,它将在每个MediatR请求上运行,但只会注入使用泛型类型或指定TRequest类型的IRequestPreProcessor的实现,因为我们的PreProcessFirstCommand类具有:
public class RequestPreProcessValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IRequestPreProcessor<TRequest>> _preProcessors;
public RequestPreProcessValidationBehaviour(IEnumerable<IRequestPreProcessor<TRequest>> preProcessors)
{
_preProcessors = preProcessors;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
foreach (var processor in _preProcessors)
{
await processor.Process(request, cancellationToken).ConfigureAwait(false);
}
return await next().ConfigureAwait(false);
}
}
注意:此解决方案唯一的轻微障碍是,如果您使用的是ASP .NET Core的默认依赖注入器,它将只注入一个实现IRequestPreProcessor的类并指定一个类型。
例如:
如果您有以下课程:
public class ProcessFirstCommandHandler : IRequestHandler<ProcessFirstCommand, bool>
{
public Task<bool> Handle(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("I'm inside the handler");
return Task.FromResult(true);
}
}
public class PreProcessFirstCommand : IRequestPreprocessor<ProcessFirstCommand>
{
public ProcessFirstCommandHandlerDecorator()
{
}
public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("I ran before the handler");
}
}
public class AnotherPreProcessFirstCommand : IRequestPreprocessor<ProcessFirstCommand>
{
public ProcessFirstCommandHandlerDecorator()
{
}
public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("I ran before the handler aswell!");
}
}
public class GenericPreProcessCommand<TRequest> : IRequestPreprocessor<TRequest>
{
public ProcessFirstCommandHandlerDecorator()
{
}
public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("I'm generic!");
}
}
public class AnotherGenericPreProcessCommand<TRequest> : IRequestPreprocessor<TRequest>
{
public ProcessFirstCommandHandlerDecorator()
{
}
public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("I'm generic aswell!");
}
}
使用前面提到的通用PreProcessBahviour,这将注入GenericPreProcessCommand和AnotherGenericPreProcessCommand,但只注入PreProcessFirstCommand或AnotherPreProcessFirstCommand中的一个。这似乎只是DI的限制。我已经在official github issue上留下了对MediatR创作者Jimmy Bogard的评论,所以请务必阅读并在那里做出贡献。
祝好运!