Как правильно вызывать обработчик команды/запроса из обработчика другой команды/запроса при использовании MediatR?

Нужно ли использовать такое:

private IMediator _mediator;
protected IMediator Mediator => _mediator ??= HttpContext.RequestServices.GetService<IMediator>();

и потом вызывать Mediator.Send(...)?

Или надо создавать экземпляр контроллера, в котором есть вызов нужной команды/запроса? Или вообще другое?


Ответы (1 шт):

Автор решения: Serafim Prozorov

Пусть у Вас есть примерно такой обработчик запроса. Он просто получает данные о продукте из БД

public class GetProductByIdQueryHandler: IRequestHandler<GetProductByIdQuery, Product>
{
    private readonly CatalogDbContext _dbContext;

    public GetProductByIdQueryHandler(CatalogDbContext dbContext) => _dbContext = dbContext;

    public Task<Product> Handle(GetProductByIdQuery query, CancellationToken ct) => 
        _dbContext.Products.SingleOrDefaultAsync(product => product.Id == query.Id, ct);
}

И есть обработчик команды AddProductToBasketCommand, который, добавляет товар в корзину, а для этого надо получить цену этого товара, логично применить для этого GetProductByIdQueryHandler, это делается так:

public class AddProductToBasketCommandHandler : IRequestHandler<AddProductToBasketCommand>
{
    private readonly BasketDbContext _dbContext;
    private readonly IMediator _mediator;

    public AddProductToBasketCommandHandler(CatalogDbContext dbContext, IMediator mediator)
    {
        _dbContext = dbContext;
        _mediator = mediator;
    }

    public async Task<Unit> Handle(AddProductToBasketCommand command, CancellationToken ct)
    {
        // Вот здесь зовём обработчика GetProductByIdQuery
        var product = await _mediator.Send(new GetProductByIdQuery {Id = command.ProductId}, ct);

        // Здесь делаем с этим продуктом что-то...
    }
}

Вообще, и паттерн медиатор в целом и библиотека MediatR в частности о том, что компоненты вообще не знают друг о друге, то есть есть некий обработчик, который знает, как обработать запрос GetProductByIdQuery, есть другой, который знает, что делать с AddProductToBasketCommand, но друг о друге они не знают, а, если им надо воспользоваться услугами друг друга, то они просто говорят некоему посреднику: «Слушай, а найди там кого-нибудь, кто может обработать вот этот запрос/команду, пусть сделает, что надо и передаст через тебя результат», это позволяет создавать приложения с очень слабой связью между компонентами.

P.S. Контроллеры, о которых Вы упомянули, здесь совсем не при чём, вообще веб-фреймворк, которым пользуетесь надо расценивать, как нечто, что может авторизовать запрос и сериализовать/десериализовать данные, не более и создавать контроллеры руками точно не стоит.

→ Ссылка