Возврат значимых ошибок в API с использованием шаблона CQRS - PullRequest
0 голосов
/ 06 июня 2018

При использовании шаблона Mediatr мне кажется довольно сложным возвращать значимые ошибки в контроллер API.Давайте возьмем метод OrdersController.CancelOrder в качестве примера ( src ).

В этом примере они «только» возвращают Ok() и BadRequest().В таком случае, как они будут возвращать ошибки типа «Этот заказ не существует» (404) ИЛИ «этот заказ был отправлен» (400) (...).

Мы могли бы ввести новый класс с именем Result, содержащий как возвращаемые значения (если таковые имеются), так и сообщения об ошибках.В этом случае все ваши команды запросов должны возвращать Result<YourModel>.Мы также можем добавить код прямо внутри контроллера.Я не могу определиться, оба решения имеют свои плюсы и минусы.

Что вы думаете об этом?

Thx Seb

1 Ответ

0 голосов
/ 06 июня 2018

Именно так я обычно и делаю, используя Mediatr.
Возвращает класс-обертку.

Если мы возьмем пример CancelOrder примера eShopOnContainers, у меня будет команда, возвращающая CancelOrderCommandResult

public class CancelOrderCommand : IRequest<CancelOrderCommandResult>
{ }

CancelOrderCommandResult может быть чем-то вроде этого:

public class CancelOrderCommandResult
{
    public CancelOrderCommandResult(IEnumerable<Error> errors)
    {
        Success = false;
        Errors = errors;
    }

    public CancelOrderCommandResult(bool success)
    {
        Success = success;
    }

    public bool Success {get; set;}

    public IEnumerable<Error> Errors {get; set;}
}

Я пропустил класс Error, но это мог быть просто POCO, содержащий информацию об ошибке,код ошибки и т. д. *

Затем наш обработчик становится

public class CancelOrderCommandHandler : IRequestHandler<CancelOrderCommand, CancelOrderCommandResult>
{
    private readonly IOrderRepository _orderRepository;

    public CancelOrderCommandHandler(IOrderRepository orderRepository)
    {
        _orderRepository = orderRepository;
    }

    public async Task<bool> Handle(CancelOrderCommand command, CancellationToken cancellationToken)
    {
        var orderToUpdate = await _orderRepository.GetAsync(command.OrderNumber);

        if(orderToUpdate == null)
        {
            return false;
        }

        try 
        {
            orderToUpdate.SetCancelledStatus();
            await _orderRepository.UnitOfWork.SaveEntitiesAsync();

            //iff success, return true
            return new CancelOrderCommandResult(true);
        }
        catch (Exception ex)
        {
            var errors = MapErrorsFromException(ex);
            return new CancelOrderCommandResult(errors)
        }
    }
}

Опять же, MapErrorsFromException опущен для краткости, но вы можете даже вставить это как зависимость.

В вашем контроллере, когда вы звоните _mediator.Send, вы теперь получаете CancelOrderCommandResult - и если .Success - true, возвращайте 200, как и раньше.

В противном случае у вас есть набор ошибок - скоторые вы можете принять решение о том, что вернуть - 400, 500 и т. д ...

...