如何装饰MediatR处理程序

问题描述 投票:0回答:1

我想装饰一个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);
    }
}
c# autofac cqrs mediatr
1个回答
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");
        }
}

这将由您的通用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的类并指定一个类型。

例如:

如果您有以下课程:

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);
    }
}

PreProcessFirstCommand.cs

public class PreProcessFirstCommand : IRequestPreprocessor<ProcessFirstCommand>
{

        public ProcessFirstCommandHandlerDecorator()
        {

        }

        public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
        {
            Console.WriteLine("I ran before the handler");
        }
}

AnotherPreProcessFirstCommand.cs

public class AnotherPreProcessFirstCommand : IRequestPreprocessor<ProcessFirstCommand>
{

            public ProcessFirstCommandHandlerDecorator()
            {

            }

            public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
            {
                Console.WriteLine("I ran before the handler aswell!");
            }
 }

GenericPreProcessCommand.cs

public class GenericPreProcessCommand<TRequest> : IRequestPreprocessor<TRequest>
{

            public ProcessFirstCommandHandlerDecorator()
            {

            }

            public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
            {
                Console.WriteLine("I'm generic!");
            }
 }

另一个通用PreProcess Command.cs

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的评论,所以请务必阅读并在那里做出贡献。

祝好运!

© www.soinside.com 2019 - 2024. All rights reserved.