一.返回類型 ASP.NET Core 提供以下 Web API Action方法返回類型選項,以及說明每種返回類型的最佳適用情況: (1) 固定類型 (2) IActionResult (3) ActionResult<T> 1.1 固定類型 最簡單的操作是返回基元或複雜數據類型(如 string ...
一.返回類型
ASP.NET Core 提供以下 Web API Action方法返回類型選項,以及說明每種返回類型的最佳適用情況:
(1) 固定類型
(2) IActionResult
(3) ActionResult<T>
1.1 固定類型
最簡單的操作是返回基元或複雜數據類型(如 string
或自定義對象類型)。 請參考以下Action,該Action返回自定義 Product
對象的集合:
[HttpGet] public IEnumerable<Product> Get() { return _repository.GetProducts(); }
適用場景:在執行Action期間,無需要根據條件判斷返回不同類型,只返回固定類型即可滿足要求。 上述操作不接受任何參數,因此不需要參數約束驗證。
1.2 IActionResult類型
當Action方法中可能有多個 ActionResult 返回類型時,適合使用 IActionResult 返回類型。ActionResult 類型可以表示多種 HTTP 狀態代碼。 屬於此類別的一些常見返回類型包括:BadRequestResult (400)、NotFoundResult (404) 和 OkObjectResult (200)。
由於Action方法中有多個返回類型和路徑,因此必須使用 [ProducesResponseType] 特性。 此特性可針對 Swagger 等工具生成的 API 幫助頁生成更多描述性響應詳細信息(上篇有介紹)。 [ProducesResponseType] 指示Action將返回的已知類型和 HTTP 狀態代碼。
下麵是一個同步Action,該Action方法中可能有兩種返回類型:
[HttpGet("{id}")] [ProducesResponseType(typeof(Product), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public IActionResult GetById(int id) { if (!_repository.TryGetProduct(id, out var product)) { return NotFound(); } return Ok(product); }
下麵是一個非同步Action,該Action方法中可能有兩種返回類型:
[HttpPost] [ProducesResponseType(typeof(Product), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task<IActionResult> CreateAsync([FromBody] Product product) { if (product.Description.Contains("XYZ Widget")) { return BadRequest(); } await _repository.AddProductAsync(product); return CreatedAtAction(nameof(GetById), new { id = product.Id }, product); }
適用場景:當Action方法中可能有多個 ActionResult 返回類型時,適合使用 IActionResult 返回類型。
1.3 ActionResult<T>
ASP.NET Core 2.1 引入了 ActionResult<T> 返回類型。 它支持返回從 ActionResult 派生的類型或返回固定類型。ActionResult<T> 提供以下優勢:
(1) 簡化ProducesResponseType 例如:[ProducesResponseType(200, Type = typeof(Product))]
可簡化為 [ProducesResponseType(200)]
(2) 隱式強制轉換運算符,將 T 轉換為 ObjectResult,也就是將 return new ObjectResult(T); 簡化為 return T;
下麵是同步示例,(1)簡化ProducesResponseType,(2)返回隱式轉換。
[HttpGet("{id}")] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult<Product> GetById(int id) { if (!_repository.TryGetProduct(id, out var product)) { return NotFound(); } // return new ObjectResult(product); return product; }
下麵是非同步示例:
[HttpPost] [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); }
適用場景:對比IActionResult類型適用場景,它提供了二種優勢。
最後建議:不要用特定類型返回。 對於有返回類型的使用ActionResult<T>,相反對於沒有返回類型的使用IActionResult。 二者使用在“ asp.net core系列 36 WebAPI 搭建詳細示例”中有介紹。
二.響應數據的格式化
響應數據是:response返回到客戶端的數據。在ASP.NET Core MVC 中,包含對固定格式(json,xml,string..)或根據客戶端規範(Accept)來設置響應數據格式的內置支持。預設返回json數據格式。
2.1 設置固定格式的action結果
對於返回固定格式,例如返回JsonResult 和 ContentResult。這樣api向客戶端始終返回固定的格式,不考慮客戶端的Accept選項設置。JsonResult 始終返回josn數據格式, ContentResult始終返回純文本數據格式。如果不需要Action返回固定數據格式,可以返回IActionResult ,這樣可以有多種選擇的數據格式。預設是json數據格式。
(1) 返回json格式的數據,使用fiddler請求url,返回客戶端json格式數據,如下圖:
/// <summary> /// 返回固定的json格式字元串 /// </summary> /// <returns></returns> [HttpGet("Get")] public JsonResult Get() { return Json(_context.TodoItems.ToList()); }
(2) 返回純文本格式數據,使用fiddler請求url,返回客戶端字元串,如下圖
/// <summary> /// 返回固定的字元串格式 /// </summary> /// <returns></returns> [HttpGet("Message")] public ContentResult Message() { return Content("hello"); }
2.2 返回格式協商
在公開的api的場景,請求方(客戶端)在獲取數據時,他們可能要求返回自己想要的數據格式。這樣就不能使用固定的數據格式(一般也不推薦)。當客戶端指定 Accept 標頭時,就可以實現內容協商,對於內容協商返回數據格式由 ObjectResult
實現 。
下麵的案例中,返回IActionResult,返回的數據格式,由ObjectResult
來確定,預設是json數據格式。
[HttpGet("{id}", Name = "GetTodoItem")] public async Task<ActionResult<TodoItem>> GetTodoItem(long id) { var todoItem = await _context.TodoItems.FindAsync(id); if (todoItem == null) { //返回狀態碼404,打包到了ObjectResult中 return NotFound(); } //返回實體,打包到了ObjectResult中 return todoItem; }
客戶端通過指定Accept: application/xml,希望返回xml數據格式,但還是json數據格式(見下圖)。這是因為:
(1) 預設情況下,當框架檢測到請求來自瀏覽器時,它將忽略 Accept
標頭轉而以應用程式的配置預設格式。
(2) 如果請求指定 XML,但是未配置 XML 格式化程式,那麼將使用 JSON 格式化程式。
如果應用程式要服從瀏覽器 accept 標頭,可以將此配置為 MVC 配置的一部分,方法是在 Startup.cs 中以 ConfigureServices 方法將 RespectBrowserAcceptHeader 設置為 true,並設置以客戶端格式優先。
services.AddMvc(options => { //優先客戶端指定數據格式 options.RespectBrowserAcceptHeader = true; //添加xml數據格式的輸出 options.OutputFormatters.Add(new XmlSerializerOutputFormatter()); });
如下圖所示,客戶端指定Accept: application/xml,服務端就返回了xml數據格式,同樣指定Accept: application/json ,服務端就返回json數據格式。
2.3 強制執行固定格式
如果需要限制固定Action的響應格式,那麼可以應用 [Produces] 篩選器。 [Produces] 篩選器指定特定action(或控制器)的響應格式。 如同大多篩選器,這可以在action層面、控制器層面或全局範圍內應用。 這樣格式協商就失敗,始終返回json數據格式。
//控制器層面強制使用json格式 [Produces("application/json")] [ApiController]//添加特性,代表是一個Web API控制器 public class TodoController : Controller //action層面強制返回json格式 [Produces("application/json")] [HttpGet] public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems() { //using Microsoft.EntityFrameworkCore; return await _context.TodoItems.ToListAsync(); }
2.4 特殊情況格式化程式
如果要過濾客戶端Accept請求的某些類型,例如過濾text/plain。string 預設是text/plain類型,如果刪除TextOutputFormatter
,則string
返回類型 是406 Not Acceptable。
//下麵對返回string字元串或返回http 204的進行過濾,代碼對應如下: services.AddMvc(options => { options.OutputFormatters.RemoveType<TextOutputFormatter>(); options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>(); });
2.5 響應格式URL映射
當格式協商配置好了以後,客戶端可以請求特定格式作為URL的一部分。下麵是Url映射的配置示例。
[FormatFilter] public class ProductsController { [Route("[controller]/[action]/{id}.{format?}")] public Product GetById(int id)
當客戶端訪問該url,返回預設數據格式:
/products/GetById/5
當客戶端訪問該url,返回json數據格式:
/products/GetById/5.json
當客戶端訪問該url,返回xml數據格式:
/products/GetById/5.xml
參考文獻: