前言
在實際應用場景中我們常常要對介面的入參進行校驗, 例如分頁大小是否正確, 必填引數是否已經填寫等等.
最簡單的實現方式如下圖, 這種在實際開發中程式碼過於冗餘, 而且不靈活. 今天介紹一種統一引數校驗的方式: System.ComponentModel.Annotations
教程
一. 使用nuget安裝 System.ComponentModel.Annotations
二. 在請求引數上加屬性
頭部引用
using System.ComponentModel.DataAnnotations;
原生的元件上就提供了豐富的引數校驗規則, 也支援自定義規則.
- Required 必填, 示例:[Required(ErrorMessage = "ID是必填項")] 需要注意除了string型別的其他的值型別由於會賦予預設值, 所以加這個屬性的時候值型別欄位需要設定為可為空 例如 int? Id {get;set;}
- Range 範圍校驗, 示例 [Range(1,99999999,ErrorMessage ="請輸入正確的頁碼")]
- Compare 比較 與指定的欄位值進行比較 [Compare("MyOtherProperty")]兩個屬性必須相同值,比如我們要求使用者重複輸入兩次郵件地址時有用
- CreditCard 信用卡號
- EmailAddress 是否為郵件
- EnumDataType 校驗列舉型別 示例: [EnumDataType(typeof(EnumModels.ResponseHttpCode),ErrorMessage = "未知的型別")]
- MaxLength 最大長度, 示例: [MaxLength(50,ErrorMessage = "暱稱不能超過50個字")]
- MinLength 最小長度 , 示例: [MinLength(2,ErrorMessage = "暱稱不能少於2個字")]
- StringLength 字串長度不能超過給定的最大長度,也可以指定最小長度. 示例: [StringLength(50, ErrorMessage = "暱稱只能介於2-50個字", MinimumLength = 2)]
- Url url格式, 示例: [Url(ErrorMessage = "連結格式錯誤")]
- RegularExpression 正規表示式 示例: [RegularExpression(@"^[1]{1}[3,4,5,6,7,8,9]{1}\d{9}$", ErrorMessage = "手機號碼格式錯誤")]
三. 介面使用
請求引數
public class IdHeader { /// <summary> /// Id /// </summary> [Required(ErrorMessage = "請填寫id")] public string Id { get; set; } }
介面
public IActionResult TestCode([FromBody]IdHeader req) { return Ok(new { req.Id }); }
在.net core 3.1中 我們請求時給id不負值, 將返回以下結果
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "|ae306434-48bb5a7d72259168.", "errors": { "Id": [ "請填寫id" ] } }
一般情況我們需要返回自己定義的格式, 所以我們需要先關閉自動校驗, .net core 2.x和 .net framework預設是不自動校驗的, 無需關閉
在Startup.cs裡的ConfigureServices 新增如下程式碼關閉自動校驗
//關閉引數自動校驗,我們需要返回自定義的格式 services.Configure<ApiBehaviorOptions>((o) => { o.SuppressModelStateInvalidFilter = true; });
然後我們需要新增 OnActionExecuting 過濾器
新增過濾器
public class ActionFilter : IActionFilter { /// <summary> /// action執行前 /// </summary> /// <param name="context"></param> public void OnActionExecuting(ActionExecutingContext context) { //校驗引數 if (!context.ModelState.IsValid) { var errorMsg = context.ModelState.Values.SelectMany(e => e.Errors).Select(e => e.ErrorMessage).FirstOrDefault(); context.Result = new OkObjectResult(new { Code = 702, Msg = string.IsNullOrWhiteSpace(errorMsg) ? "引數校驗錯誤" : errorMsg, Data = new {} }); return; } } /// <summary> /// action執行後 /// </summary> /// <param name="context"></param> public void OnActionExecuted(ActionExecutedContext context) { } }
.net core 使用過濾器, 在Startup.cs裡的ConfigureServices 新增如下程式碼使用過濾器
services.AddMvc(o => { //action 過濾器 o.Filters.Add<ActionFilter>(); })
.net webapi 使用過濾器, 在 webapiConfig.cs 裡的 Register 裡新增程式碼
config.Filters.Add(new App_Start.ActionFilter());//action過濾器
最後的結果
{ "code": 702, "msg": "請填寫id", "data": {} }
這樣我們就可以自定義我們返回引數
四. 自定義引數校驗
雖然官方已經提供了不少驗證方法, 但是可能還不夠我們使用, 例如身份證號, 行政區劃程式碼等等.
電話號碼官方已經提供了一個,但是不適用於我們中國, 我們以校驗中國手機號碼為例, 來講自定義引數校驗
主要方法是: 自定義類 , 繼承 ValidationAttribute, 然後複寫 IsValid
/// <summary> /// 是否為中國手機號碼 /// </summary> public class ChinaMobilPhoneAttribute : ValidationAttribute { /// <summary> /// 複寫 /// </summary> /// <param name="value"></param> /// <returns></returns> public override bool IsValid(object value) { if (!(value is string)) return false; var val = (string)value; return Regex.IsMatch(val, @"^[1]{1}[3,4,5,6,7,8,9]{1}\d{9}$"); } }
然後入參校驗
/// <summary> /// Id 具體值請參考具體介面 /// </summary> [ChinaMobilPhone(ErrorMessage = "請填寫正確的手機號")] public string PhoneNumber { get; set; }
測試
錯誤結果
正確結果
通過以上方式我們輕鬆實現各種引數校驗