Как украсить MediatR Handler - PullRequest
       84

Как украсить MediatR Handler

0 голосов
/ 07 февраля 2019

Я хочу украсить только один обработчик MediatR.Я пытался использовать Behaviors, но Behaviors внедряет декоратор для каждого обработчика, который реализует 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<,>));
    }
}

Вопрос: Как добавить декоратор, который будет выполняться перед вызовом метода Handle класса ProcessFirstCommandHandler, а не для других классовкоторые реализуют IRequestHandler.

Как сделать метод дескриптора нижеприведенного класса, вызываемый первым перед ProcessFirstCommandHandler, когда объекты 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);
    }
}

1 Ответ

0 голосов
/ 01 марта 2019

Если все, что вы пытаетесь сделать, это запустить что-то до вызова вашего обработчика, тогда вы можете использовать Поведения для реализации этого.Я знаю, что вы сказали, что пытались сделать это раньше, однако вы можете создать генерирующее поведение, которое запускает все реализации 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 он будетТолько когда-нибудь внедрить один из классов, которые реализуют 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!");
            }
 }

AnotherGenericPreProcessCommand.cs

1032

Используя общий PreProcessBahviour, упомянутый ранее, он будет внедрять как GenericPreProcessCommand , так и AnotherGenericPreProcessCommand , но только один из PreProcessFirstCommand или AnotherPrePromandir.Кажется, это просто ограничение DI.Я оставил комментарии для создателя MediatR Джимми Богарда на официальном выпуске github , так что обязательно прочитайте и внесите свой вклад туда же.

Удачи!

...