C# .net framework .net core 3.1 請求引數校驗, DataAnnotations, 自定義引數校驗

範斯發表於2020-06-12

前言

在實際應用場景中我們常常要對介面的入參進行校驗, 例如分頁大小是否正確, 必填引數是否已經填寫等等. 

最簡單的實現方式如下圖, 這種在實際開發中程式碼過於冗餘, 而且不靈活. 今天介紹一種統一引數校驗的方式: 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; }

測試

錯誤結果

 

 正確結果

 

 通過以上方式我們輕鬆實現各種引數校驗

相關文章