前言
在實際應用場景中我們常常要對接口的入參進行校驗, 例如分頁大小是否正確, 必填參數是否已經填寫等等.
最簡單的實現方式如下圖, 這種在實際開發中代碼過於冗余, 而且不靈活. 今天介紹一種統一參數校驗的方式: 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不賦值, 將返回以下結果 , 因為繼承了apicontroller會自動校驗
{ "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; }
測試
錯誤結果
正確結果
通過以上方式我們輕松實現各種參數校驗