我只想装饰一个MediatR处理程序。我尝试使用行为,但“行为”为实现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对象执行此行_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);
}
}
答案 0 :(得分:1)
如果您要做的只是在调用处理程序之前先运行一些东西,那么您可以利用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");
}
}
这将由您的通用PreProcessorBehaviour激活,它将在每个MediatR请求上运行,但仅会注入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的默认Dependency Injector,它将仅注入实现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 < / em>。这似乎只是DI的限制。我在official github issue上为MediatR创作者吉米·博加德(Jimmy Bogard)留下了评论,因此请务必阅读并在其中做出贡献。
祝你好运!
答案 1 :(得分:0)
尽管在大多数情况下推荐使用IRequestPreProcessor
作为首选方法,但您仍然可以直接调用IoC容器来添加装饰器。
例如,使用SimpleInjector:
container.RegisterDecorator(typeof(IRequestHandler<,>), typeof(HandlerDecorator<,>));