【发布时间】:2020-04-13 19:26:02
【问题描述】:
我是构建 API 的新手。我的项目包含三个典型层:控制器、负责业务逻辑的服务和访问数据的存储库。在执行特定操作之前,到达我的控制器的每个请求都必须经过一些验证过程。例如,请检查以下代码:
[HttpPost]
public async Task<ActionResult<TicketDTO>> CreateTicketAsync([FromBody] CreateTicketDTO ticket)
{
try
{
if (ticket.Events == null)
{
return BadRequest(new {Message = _localizer["LackOfEventsErrorMessage"].Value});
}
var user = await _userService.GetUserByIdAsync(ticket.UserId);
if (user == null)
{
return NotFound(new { Message = _localizer["UserNotFoundErrorMessage", ticket.UserId].Value });
}
var invalidTicket = await _ticketService.CheckHasUserPlayedAnyOfGamesBeforeAsync(ticket);
if (invalidTicket)
{
return BadRequest(new { Message = _localizer["EventsRepeatedByUserErrorMessage"].Value });
}
var createdTicket = await _ticketService.AddTicketAsync(ticket);
if (createdTicket == null)
{
return BadRequest(new { Message = _localizer["TicketNotCreatedErrorMessage"].Value });
}
return CreatedAtAction(nameof(GetTicketById), new {ticketId = createdTicket.TicketId}, createdTicket);
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError,
new
{
Message = ex.InnerException != null
? $"{ex.Message} {ex.InnerException.Message}"
: ex.Message
});
}
}
这是我的控制器方法之一。在将票证保存到数据库之前,它必须通过一些检查。票的所有者必须存在,否则我返回未找到用户等。问题是我不太喜欢这种验证请求的方式。该方法很混乱,而且可读性不强。我想知道什么是验证请求的好方法,并在出现问题时做出正确反应(例如,如果数据库中没有用户,则返回“UserNotFoundErrorMessage”等。单个 catch 块并不能解决我的问题。我也不希望那里有多个 catch 块,我认为这也很乱。我错了吗?) 我想知道附加的 sn-p 是否违反了一些干净的代码规则?代码应该是什么样子?我做错了什么?
【问题讨论】:
-
你可以做一些重构,但你的方法非常好,一点也不乱。不过,你问的很自以为是。你可以附加的东西是
??运算符 ->ticket.Events ?? throw new Exception... 或者随便什么 -
我会将它下推到服务层并实现一个
Validation<T>来跟踪其有效性。如果有效,它将有一个T,如果不是,它将有一个IEnumerable<Error>。 -
如果你有很多验证要做,你可以看看 Fluent Validation。可能会帮助您从控制器中获取一些逻辑。
标签: c# asp.net-core controller coding-style