c# - 如何装饰 MediatR 处理程序

标签 c# autofac cqrs mediatr

我只想装饰一个 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);
    }
}
预处理第一命令.cs
public class PreProcessFirstCommand : IRequestPreprocessor<ProcessFirstCommand>
{    
    public ProcessFirstCommandHandlerDecorator()
    {

    }

    public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
    {
        Console.WriteLine("I ran before the handler");
    }
}
另一个PreProcessFirstCommand.cs
public class AnotherPreProcessFirstCommand : IRequestPreprocessor<ProcessFirstCommand>
{
    public ProcessFirstCommandHandlerDecorator()
    {

    }

    public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
    {
        Console.WriteLine("I ran before the handler as well!");
    }
 }
通用预处理命令.cs
public class GenericPreProcessCommand<TRequest> : IRequestPreprocessor<TRequest>
{
    public ProcessFirstCommandHandlerDecorator()
    {

    }

    public Task Process(ProcessFirstCommand request, CancellationToken cancellationToken)
    {
        Console.WriteLine("I'm generic!");
    }
 }
另一个通用PreProcessCommand.cs
public 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/

相关文章:

c# - WPF 应用程序的内容调整大小事件

microservices - 如何使用 CQRS 和基于事件溯源的微服务将新创建的资源提供给客户端

asp.net-core - 如何为 ASP.NET Core 注册和使用 MediatR 管道处理程序?

c# - OpenFileDialog.ShowDialog() 在 Silverlight 中引发 InvalidOperationException

c# - Visual Studio C# 2010 速成版中的对象浏览器在哪里?

c# - 在 asp.net mvc 3 中管理每个 session 和请求的 AutoFac 生命周期范围

c# - 为参数的具体名称注册字符串值

angular - ngxs 异步操作的成功/失败操作事件的目的是什么?

c# - 在 Mono 中加载 X509Certificate2 会引发 CryptographicException "Input data cannot be coded as a valid certificate"

asp.net-core - 请求范围是否有匹配生命周期的标签?