使用Mediatr模式时,我发现将有意义的错误返回给API控制器非常具有挑战性。我们以OrdersController.CancelOrder
方法为例(src)。
在这个例子中,他们只是"返回Ok()
和BadRequest()
。在这种情况下,他们将如何返回错误,如"此订单不存在" (404)或者"此订单已经发货" (400)(...)。
我们可以引入一个名为Result
的新类,它包含返回的值(如果有的话)和可能的错误消息。在这种情况下,所有命令,查询都应返回Result<YourModel>
。我们还可以直接在控制器中添加代码。我无法下定决心,两种解决方案都有利有弊。
你怎么看?
THX SEB
答案 0 :(得分:1)
这正是我倾向于使用Mediatr的方式 返回一个包装类。
如果我们采用eShopOnContainers示例CancelOrder
示例,我将获得该命令,返回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
为真,则返回之前的200。
否则,你会收到一些错误 - 你可以用它来做出一些关于返回的决定 - 400,500等...