为多个可能的结果建模ASP.NET Core Controller更新

时间:2019-04-09 18:13:40

标签: c# asp.net-core

我使用https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api?view=aspnetcore-2.2&tabs=visual-studio作为参考,并对更新的处理方式很感兴趣。

为更新方法提供以下代码:

public class Todo
{
    public int Id { get; set; }

    public string Title { get; set; }

    public bool Completed { get; set; }
}

public class UpdateTodoRequest
{
    public string Title { get; set; }

    public bool Completed { get; set; }
}

public async Task<ActionResult> UpdateAsync([FromRoute] id, UpdateTodoRequest todoUpdateRequest)
{
    if (todo == null)
    {
        return BadRequest();
    }

    var result = await _todoService.UpdateAsync(id, todoUpdateRequest);

    // Here I can have three possible results
    //  1. Todo with that Id was not found - 404
    //  2. Todo didn't pass validation rules - 400 (together with list of rules that didn't pass)
    //  3. Everything was successful - 204
}

我应该如何为_todoService.UpdateAsync方法签名建模,以便它可以处理我列出的所有三种情况?

我可以将其重构如下:

public async Task<ActionResult> UpdateAsync([FromRoute] id, UpdateTodoRequest todoUpdateRequest)
{
    if (todo == null)
    {
        return BadRequest();
    }

    // Getting the whole Todo by id coming from route
    var todo = await _todoService.GetById(id);

    if (todo == null)
    {
        // Returning 404 here
        return NotFound();
    }

    // Updating values coming from request to todo taken from service
    todo.Title = todoUpdateRequest.Title;
    todo.Completed = todo.Completed;

    // Result = boolean for success/failure
    var result = await _todoService.UpdateAsync(todo);

    return result ? NoContent() : BadRequest();
}

在此版本中,我几乎可以处理所需的案例:

  • 如果没有该ID,我可以得到404
  • 我可以返回400个验证问题(但是没有验证条件
  • 如果更新成功,我会得到204

那么我该如何为我的服务建模,以便控制器可以处理以上所有这三种情况?同样,我乐于接受任何建议以不同的方式做事,或者公开讨论已被讨论至死的SO问题。

我还认为,使用功能世界中的Either Monad:https://mikhail.io/2016/01/validation-with-either-data-type-in-csharp/来指示成功/验证错误并根据其结果返回正确的响应类型是很有意义的。

1 个答案:

答案 0 :(得分:1)

由于该操作中有多种返回类型和路径,因此必须自由使用[ProducesResponseType]属性。此属性为由Swagger之类的工具生成的API帮助页面生成更具描述性的响应详细信息。 [ProducesResponseType]表示该操作将返回的已知类型和HTTP状态代码。请参阅here

您可以使用下面的代码返回三种响应的类型。

[HttpPut("{id}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> UpdateAsync([FromRoute] id, UpdateTodoRequest todoUpdateRequest)