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 返回型別與基元或複雜返回型別混合。 要支援此類操作,必須使用 IActionResult 或 ActionResult。 本文件中提供了多個返回型別的幾個示例。
返回 IEnumerable<T>
或 IAsyncEnumerable<T>
ASP.NET Core 在將操作寫入響應之前,對返回 IEnumerable 的結果進行緩衝。 考慮將操作簽名的返回型別宣告為 IAsyncEnumerable
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
響應標頭。
例如,以下模型指明請求必須包含 Name
和 Description
屬性。 未在請求中提供 Name
和 Description
會導致模型驗證失敗。
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
以下部分比較 ActionResult
和 IActionResult
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
進行推斷。 -
隱式強制轉換運算子支援將
T
和ActionResult
均轉換為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
響應標頭。