快讀《ASP.NET Core技術內幕與項目實戰》WebApi3.1:WebApi最佳實踐

本節內容,涉及到6.1-6.6(P155-182),以WebApi說明為主。主要NuGet包:無

 

一、創建WebApi的最佳實踐,綜合了RPC和Restful兩種風格的特點

 1 //定義Person類和ErrorInfo類
 2 public record Person(int Id, string Name, int Age);
 3 public record ErrorInfo(int Code, string? Message);
 4 
 5 
 6 //定義控制器和一個Get方法
 7 [ApiController]
 8 [Route("api/[controller]/[action]")] 
 9 public class TestController : ControllerBase
10 {
11     //模擬一個persons數據集合
12     private List<Person> persons = new List<Person>();
13     public TestController()
14     {
15         var p1 = new Person(1, "ZS", 25);
16         var p2 = new Person(2, "LS", 18);
17         var p3 = new Person(3, "WU", 35);
18         var p4 = new Person(4, "ZL", 46);
19         persons.Add(p1);
20         persons.Add(p2);
21         persons.Add(p1);
22         persons.Add(p1);
23 
24     }
25 
26     [HttpGet("{id}")]
27     public ActionResult<Person> GetPersonById(int id)
28     {
29         if (id < 1)
30         {
31             return BadRequest(new ErrorInfo(1, "id必須是正數"));
32         }
33         else if(id > 4)
34         {
35             return NotFound(new ErrorInfo(2, "查無此人"));
36         }
37         else
38         {
39             return persons.FirstOrDefault(p => p.Id == id);
40         }
41     }
42 }

代碼解讀:

8行:統一設置控制器類的路徑為[controller]/[action],控制器+方法名,前綴api可省略。這個方式傾向於RPC風格,可以直接知道API的意圖

9行:因為不需要MVC中的視圖功能,所以WebApi的控制器繼承ControllerBase即可,ControllerBase中定義了Response、Request、HttpContext等屬性成員來獲取請求和響應信息,以及BadRequest、NotFound、OK等方法來快速設置響應報文。

26行:所有方法,都須加上Http方法的Attribute,主要有[HttpGet]、[HttpPost]、[HttpPut]、[HttpDelete],分別進行查詢、新增、更新、刪除操作。這不僅有利於明確操作方法的請求類型,也有利於使用Swagger+OpenApi來生成文檔。使用Swagger時,如果沒有標註,會報錯,如果確定這個方法不生成Api,可以標註[ApiExplorerSettings(IgnoreApi = true)]

27行:返回值如果是普通類型,直接返回即可,會自動序列化為JSON格式,但如果返回值為複雜類型,需要使用ActionResult<T>泛型類型來包裝

31,35行:使用BadRequest、NotFound、Ok等方法,快速設置響應數據,可以和ActionResult<T>很好的結合使用。其中BadRequest的響應狀態碼為400,NotFound為404,Ok為200。同時,方法參加為一個自定義ErrorInfo對象,包括錯誤碼和錯誤信息兩個屬性,進一步說明具體的錯誤信息。方法會自動將ErrorInfo對象序列化為JSON對象

39行:直接返回對象,因為方法設置了返回值為ActionResult<T>,自動將複雜對象序列化為JSON對象。這裡嚴謹一點,應該判斷一下是否為null

補充說明:

①HTTP的四個常用請求謂詞的特徵:GET/Put/DELETE是冪等操作,網關或網絡請求組件會對失敗請求自動重試;POST是非冪等的,需要注意重複提交的情況;GET請求的響應可以被緩存,而其它請求不能被緩存;GET和DELETE不支持請求體傳參,POST和PUT支持

②HTTP的常用狀態碼:401,需要身份認證的但是沒有提供;403,需要權限的但沒有權限;404,請求的資源不存在;400,請求參數錯誤或其它業務錯誤;200,請求處理成功

③如果方法中調用了異步方法,則返回值為async Task<ActionResult<T>>

 

二、Api方法參數的最佳實踐

1、通過URL

 

//通過HttpGet的參數設置請求路徑,其中{}內的,為路徑參數
//如果方法參數的名稱和{}內的不一樣,則參數使用[FromRoute]指定
//如果請求參數schoolName為aaa,classNo為bbb
//則請求路徑為api/Test/GetAll/school/aaa/class/bbb
[HttpGet("school/{schoolName}/class/{classNo}")]
public ActionResult<Student[]> GetAll(string schoolName, [FromRoute(Name = "classNo")] string classNum){}

 

 

2、通過QueryString

//從Query中獲取實參時,就不需要在HttpGet中設置路徑
//如果請求參數名稱和方法行參名稱不同,則要指定[FromQuery]的Name屬性
//假設請求參數schoolName為aaa,classNo為bbb
//則請求地址為api/Test/GetAll?schoolName=aaa&classNum=bbb
[HttpGet]
public ActionResult<Student> GetAll(string schoolName, [FromQuery(Name = "classNo")]string classNum){}

 

3、通過請求體

//方法參數為複雜類型時,自動序列化為JSON,通過請求體發送
//參數中可加、可不加[FromBody]
//請求地址為api/Test/AddNew
[HttpPost]
public ActionResult<Student> AddNew(Student studentDto)
{
    persons.Add(studentDto);
    return Ok(studentDto);
}

 

4、除了FromRoute、FromQuery、FromBody之外,還有FromForm、FromHeader等

 

5、傳遞參數最佳實踐:

①GET和DELETE請求,參數使用QueryString

②POST請求,參數使用請求體

③PUT請求,定位參數使用QueryString,DTO參數使用請求體

④GET請求,如果參數內容超過URL長度限制,則把請求改為PUT,並通過請求體來傳遞參數

⑤Restful風格,要求路徑參數用於定位資源,Query參數用於傳遞額外參數,但使用Query更符合中文習慣,所以URL還是比較少使用

⑥注意:請求報文頭的Content-Type要設置為application/JSON

 

 

  

特別說明:
1、本系列內容主要基於楊中科老師的書籍《ASP.NET Core技術內幕與項目實戰》及配套的B站視頻視頻教程,同時會增加極少部分的小知識點
2、本系列教程主要目的是提煉知識點,追求快准狠,以求快速複習,如果說書籍學習的效率是視頻的2倍,那麼「簡讀系列」應該做到再快3-5倍