本節內容,涉及到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倍