1. 程式人生 > 其它 >ASP.NET Core Web API 中控制器操作的返回型別

ASP.NET Core Web API 中控制器操作的返回型別

ASP.NET Core Web API 中控制器操作的返回型別

  • 專案
  • 2022/04/18
  • 7 個參與者

檢視或下載示例程式碼如何下載

ASP.NET Core 提供以下 Web API 控制器操作返回型別選項:

本文件說明每種返回型別的最佳適用情況。

特定型別

最簡單的操作返回基元或複雜資料型別(如 string 或自定義物件型別)。 請參考以下操作,該操作返回自定義 Product 物件的集合:

[HttpGet]
public List<Product> Get() =>
    _repository.GetProducts();

在執行操作期間無需防範已知條件,返回特定型別即可滿足要求。 上述操作不接受任何引數,因此不需要引數約束驗證。

如果存在多種返回型別,通常會將 ActionResult 返回型別與基元或複雜返回型別混合。 要支援此類操作,必須使用 IActionResultActionResult。 本文件中提供了多個返回型別的幾個示例。

返回 IEnumerable<T> 或 IAsyncEnumerable<T>

ASP.NET Core 在將操作寫入響應之前,對返回 IEnumerable 的結果進行緩衝。 考慮將操作簽名的返回型別宣告為 IAsyncEnumerable

以保證非同步迭代。 最終,迭代模式基於要返回的基礎具體型別。 MVC 自動對實現 IAsyncEnumerable<T> 的任何具體型別進行緩衝。

請考慮以下操作,該操作將銷售價格的產品記錄返回為 IEnumerable<Product>

[HttpGet("syncsale")]
public IEnumerable<Product> GetOnSaleProducts()
{
    var products = _repository.GetProducts();

    foreach (var product in products)
    {
        if (product.IsOnSale)
        {
            yield return product;
        }
    }
}

上述操作的 IAsyncEnumerable<Product> 等效項為:

[HttpGet("asyncsale")]
public async IAsyncEnumerable<Product> GetOnSaleProductsAsync()
{
    var products = _repository.GetProductsAsync();

    await foreach (var product in products)
    {
        if (product.IsOnSale)
        {
            yield return product;
        }
    }
}

IActionResult 型別

當操作中可能有多個 ActionResult 返回型別時,適合使用 IActionResult 返回型別。 ActionResult 型別表示多種 HTTP 狀態程式碼。 派生自 ActionResult 的任何非抽象類都限定為有效的返回型別。 此類別中的某些常見返回型別為 BadRequestResult (400)、NotFoundResult (404) 和 OkObjectResult (200)。 或者,可以使用 ControllerBase 類中的便利方法從操作返回 ActionResult 型別。 例如,return BadRequest();return new BadRequestResult(); 的簡寫形式。

由於此操作型別中有多個返回型別和路徑,因此必須自由使用 [ProducesResponseType\] 特性。 此特性可針對 Swagger 等工具生成的 Web API 幫助頁生成更多描述性響應詳細資訊。 [ProducesResponseType] 指示操作將返回的已知型別和 HTTP 狀態程式碼。

同步操作

請參考以下同步操作,其中有兩種可能的返回型別:

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Product))]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetById(int id)
{
    if (!_repository.TryGetProduct(id, out var product))
    {
        return NotFound();
    }

    return Ok(product);
}

在上述操作中:

  • id 代表的產品不在基礎資料儲存中時,則返回 404 狀態程式碼。 NotFound 便利方法作為 return new NotFoundResult(); 的簡寫呼叫。
  • 如果產品確實存在,則返回狀態程式碼 200 及 Product 物件。 Ok 便利方法作為 return new OkObjectResult(product); 的簡寫呼叫。

非同步操作

請參考以下非同步操作,其中有兩種可能的返回型別:

[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync(Product product)
{
    if (product.Description.Contains("XYZ Widget"))
    {
        return BadRequest();
    }

    await _repository.AddProductAsync(product);

    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}

在上述操作中:

  • 當產品說明包含“XYZ 小元件”時,返回 400 狀態程式碼。 BadRequest 便利方法作為 return new BadRequestResult(); 的簡寫呼叫。
  • 在建立產品後,CreatedAtAction 便利方法生成 201 狀態程式碼。 呼叫 CreatedAtAction 的替代方法是 return new CreatedAtActionResult(nameof(GetById), "Products", new { id = product.Id }, product);。 在此程式碼路徑中,將在響應正文中提供 Product 物件。 提供了包含新建產品 URL 的 Location 響應標頭。

例如,以下模型指明請求必須包含 NameDescription 屬性。 未在請求中提供 NameDescription 會導致模型驗證失敗。

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

    [Required]
    public string Name { get; set; }

    [Required]
    public string Description { get; set; }

    public bool IsOnSale { get; set; }
}

如果應用了該 [ApiController\] 特性,則模型驗證錯誤將導致400狀態程式碼。 有關詳細資訊,請參閱自動 HTTP 400 響應

ActionResult 與 IActionResult

以下部分比較 ActionResultIActionResult

ActionResult<T> 型別

ASP.NET Core 包括 web API 控制器操作的ActionResult < T >返回型別。 它使您能夠返回派生自 ActionResult 或返回 特定型別的型別。 ActionResult<T>IActionResult 型別相比,具有以下優勢:

  • 可排除 [ProducesResponseType\] 特性的 Type 屬性。 例如,[ProducesResponseType(200, Type = typeof(Product))] 簡化為 [ProducesResponseType(200)]。 此操作的預期返回型別改為根據 ActionResult<T> 中的 T 進行推斷。
  • 隱式強制轉換運算子支援將 TActionResult 均轉換為 ActionResult<T>。 將 T 轉換為 ObjectResult,也就是將 return new ObjectResult(T); 簡化為 return T;

C# 不支援對介面使用隱式強制轉換運算子。 因此,必須使用 ActionResult<T>,才能將介面轉換為具體型別。 例如,在下面的示例中,使用 IEnumerable 不起作用:

[HttpGet]
public ActionResult<IEnumerable<Product>> Get() =>
    _repository.GetProducts();

上面程式碼的一種修復方法是返回 _repository.GetProducts().ToList();

大多數操作具有特定返回型別。 執行操作期間可能出現意外情況,不返回特定型別就是其中之一。 例如,操作的輸入引數可能無法通過模型驗證。 在此情況下,通常會返回相應的 ActionResult 型別,而不是特定型別。

同步操作

請參考以下同步操作,其中有兩種可能的返回型別:

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById(int id)
{
    if (!_repository.TryGetProduct(id, out var product))
    {
        return NotFound();
    }

    return product;
}

在上述操作中:

  • 當產品不在資料庫中時返回狀態程式碼 404。
  • 如果產品確實存在,則返回狀態程式碼 200 及相應的 Product 物件。

非同步操作

請參考以下非同步操作,其中有兩種可能的返回型別:

[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<Product>> CreateAsync(Product product)
{
    if (product.Description.Contains("XYZ Widget"))
    {
        return BadRequest();
    }

    await _repository.AddProductAsync(product);

    return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}

在上述操作中:

  • 在以下情況下,ASP.NET Core 執行時返回 400 狀態程式碼 (BadRequest):
    • 已應用 [ApiController\] 屬性,且模型驗證失敗。
    • 產品說明包含“XYZ 小元件”。
  • 在建立產品後,CreatedAtAction 方法生成 201 狀態程式碼。 在此程式碼路徑中,將在響應正文中提供 Product 物件。 提供了包含新建產品 URL 的 Location 響應標頭。

其他資源