我只想装饰一个 MediatR 处理程序。我尝试使用 Behaviours,但 Behaviors 为每个实现 IRequestHandler<TRequest,TResponse>
的处理程序注入(inject)了装饰器。
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 的所有实现。
注意:以下过程也适用于在处理程序运行后实现某些内容,您只需将接口(interface)从 IRequestPreProcessor 更改为 IRequestPostProcessor
因此,如果您有命令处理程序:
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");
}
}
这将由您的通用 PreProcessorBehaviour 激活,它将在每个 MediatR 请求上运行,但只会注入(inject) IRequestPreProcessor 的实现,这些实现使用通用类型或指定 TRequest 类型,就像我们上面的 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 的默认依赖注入(inject)器,它只会注入(inject)一个实现 IRequestPreProcessor 并指定类型的类。例如:
如果您有以下类(class):
ProcessFirstCommandHandler.cs
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);
}
}
预处理第一命令.cspublic class PreProcessFirstCommand : IRequestPreprocessor<ProcessFirstCommand>
{
public ProcessFirstCommandHandlerDecorator()
{
}
public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("I ran before the handler");
}
}
另一个PreProcessFirstCommand.cspublic class AnotherPreProcessFirstCommand : IRequestPreprocessor<ProcessFirstCommand>
{
public ProcessFirstCommandHandlerDecorator()
{
}
public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("I ran before the handler as well!");
}
}
通用预处理命令.cspublic class GenericPreProcessCommand<TRequest> : IRequestPreprocessor<TRequest>
{
public ProcessFirstCommandHandlerDecorator()
{
}
public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("I'm generic!");
}
}
另一个通用PreProcessCommand.cspublic class AnotherGenericPreProcessCommand<TRequest> : IRequestPreprocessor<TRequest>
{
public ProcessFirstCommandHandlerDecorator()
{
}
public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("I'm generic aswell!");
}
}
使用前面提到的通用 PreProcessorBehavior,这将注入(inject) GenericPreProcessCommand 和 AnotherGenericPreProcessCommand,但只注入(inject) PreProcessFirstCommand 或 AnotherPreProcessFirstCommand 之一。这似乎只是 DI 的一个限制。我在 official github issue 上为 MediatR 的创建者 Jimmy Bogard 留下了评论。 ,所以请务必阅读并在那里做出贡献。
关于c# - 如何装饰 MediatR 处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54580769/