我想要在我的web api里限制一下模型的輸入,例如我的一個模型有一個title屬性,我不希望新創建title的長度超過20,我能想到的辦法只有在Controller的Action里加if語句,但這樣會讓Controller非常難看,也不利於后面新功能的擴展。
在我需要這個功能之前,我不知道這個功能叫模型驗證……還用小白提問話術百度了很久。感覺學編程可以只看書,學開發還需要有老師或者有經驗的開發者的幫助。真的非常感謝我看過的所有博客、視頻、教程等的作者,以及每一個願意犧牲自己寥寥無幾的休閑時間,來耐心的解決我提的小白問題,還有給我去百度查詢解決方案提供查詢的方向的朋友們,沒有你們,我這種沒有天賦,智商一般的學生,真的就只能Hello World了。
首先是官方文檔:
https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-3.1
官方文檔最開始的模型狀態驗證:
下面寫着web api Controller,在Controller之前加上[ApiController]這個標簽就能免去這個if語句了,我目前主要是學習web api,MVC還沒來得及學,所以這里先不管了。
然后看我們真正要用的功能:
原來直接在上面加Atrribute就行,看一下基本的Attribute類型:
內置特性
以下是一些內置驗證特性:
[CreditCard]:驗證屬性是否具有信用卡格式。
[Compare]:驗證模型中的兩個屬性是否匹配。
[EmailAddress]:驗證屬性是否具有電子郵件格式。
[Phone]:驗證屬性是否具有電話號碼格式。
[Range]:驗證屬性值是否在指定的范圍內。
[RegularExpression]:驗證屬性值是否與指定的正則表達式匹配。
[Required]:驗證字段是否不為 null。 請參閱 [Required] 屬性,獲取關於該特性的行為的詳細信息。
[StringLength]:驗證字符串屬性值是否不超過指定長度限制。
[Url]:驗證屬性是否具有 URL 格式。
[Remote]:通過在服務器上調用操作方法來驗證客戶端上的輸入。 請參閱 [Remote] 屬性,獲取關於該特性的行為的詳細信息。
在 System.ComponentModel.DataAnnotations 命名空間中可找到驗證特性的完整列表。
System.ComponentModel.DataAnnotations 命名空間(我們這里沒用到,先留下鏈接留着后續學習):
我正在實現web api的翻頁(分頁)功能,我現在的需求是讓queryString里輸入的pageNumber或者叫pageIndex不小於1,我之前試過,如果輸入小於1的,就會報500錯誤,但這個顯然是個400錯誤,是他的請求是BadRequest,這個鍋不應該服務器來背。
我發現上面的Range特性似乎非常合適,所以我用Range這個Attribute來搞一下:
我讓PageNumber的范圍在1到int能表示的最大值。(int 的System類型是Int32,short是Int16,long是Int64,所以這里我選擇Int32)。
跑起來,測試一下:
StringQuery里,pageNumber給到-1,返回了400,錯誤信息也很清晰,達成了我們的期望。
我突然有一個新需求,我想自定義Error的輸出信息,畢竟后面這個2147483647也沒什么人用得到,我主要想突出頁碼不能小於1這個事情,當然它默認的errorMessage給出了最大最小范圍,我覺得它默認的error信息是比較好的,但我還是想自定義一個。這里就要用到ErrorMessage屬性:
測試一下:
PageNumber給到0,成功返回了我們自定義的錯誤信息。
感覺這個Attribute方式不是非常靈活,我們這里的需求是可以滿足,但萬一后面我們有更復雜的需求,我們要五彩斑斕的黑和五光十色的白,怎么辦?有沒有另外一種更靈活的方式?
官方文檔給出了另外兩種方式:
方式1:
方式2:
我打算使用方式2,所以我把當前的類繼承IValidatableObject接口,把前面的Range Attribute注釋掉。然后實現IValidatableObject接口的Validate方法:
到現在,我甚至連yield這個關鍵字都不知道是什么意思,因為我C#沒怎么學,沒辦法,急着畢業找工作,趕鴨子上架,大學欠下的基礎債只能慢慢補了。這個方法寫完后,我們運行測試一下:
是我們想要的結果。
應該還有更牛比更通用的方式,但我們這里先不試了,用到的時候再去學,現在強行學了感覺能記住的概率也不大。