命名空間
System.ComponentModel.DataAnnotations
全局模型驗證,統一api響應
1、WebApi項目下新建文件夾【Custom】,新建文件夾【Filter】定義類FieldActionFilter
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using System.Linq; namespace Test.WebApi.Custom.Filter { /// <summary> /// 驗證參數 /// </summary> public class FieldActionFilter : IActionFilter { public void OnActionExecuted(ActionExecutedContext context) { //throw new NotImplementedException(); } public void OnActionExecuting(ActionExecutingContext context) { ResponseDto result = new(); if (!context.ModelState.IsValid) { var errorMessage = context.ModelState.Values.SelectMany(v => v.Errors).FirstOrDefault(); result.Success = false; result.Message = errorMessage.ErrorMessage; context.Result = new JsonResult(result); } } } }
2、StartUp注冊服務
services.AddMvc(options => { options.Filters.Add<FieldActionFilter>();//Dto參數驗證 }); services.Configure<ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; // 使用自定義模型驗證【Api接口需要添加才能生效】 });
基礎屬性
屬性名稱 | 描述 |
---|---|
Required | 標識該屬性為必需參數,不能為空 |
StringLength | 標識該字符串有長度限制,可以限制最小或最大長度 |
MaxLength | 不為null時,不能超過最大字符串長度 |
MixLength | 不為null時,不能少於最小字符串長度 |
Range | 標識該屬性值范圍,通常被用在數值型和日期型 |
Compare | 比較 - 與制定的字段值進行比較 具體見代碼 [Compare(“MyOtherProperty”)]兩個屬性必須相同值,比如我們要求用戶重復輸入兩次密碼時有用 |
RegularExpression | 標識該屬性將根據提供的正則表達式進行對比驗證 |
Remote | 服務端驗證 |
CustomValidation | 標識該屬性將按照用戶提供的自定義驗證方法,進行數值驗證 |
以下使用於表單:沒有測試過,如需使用請自己測試 | |
DisplayName | 顯示名 – 定義表單字段的提示名稱,一般用於在PropertyGrid或者DataGridView里顯示這個對象時,列名會自動顯示DisplayName定義的值,而不是字段名 |
Bind | 綁定 – 列出在將請求參數綁定到模型的時候,包含和不包含的字段 |
ScaffoldColumn | 支架列 - 在編輯表單的時候,需要隱藏起來的的字符 [ScaffoldColumn(true|false)] |
DataType | 在前端顯示的文本框類型 |
Editable | [Editable(false)] //放在主鍵上顯示不可修改 |
Validations---這個是所有驗證屬性的基類
基礎屬性【Required、Range、StringLength、Compare】
using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Test.Application.Employee.Dto { public class AddEmployeeDto { /// <summary> /// 職員姓名不能為空 /// </summary> [Required(ErrorMessage = "職員姓名不能為空")] public string EmpName { get; set; } /// <summary> /// 密碼 /// </summary> [Required(ErrorMessage = "密碼不能為空")] [StringLength(12, MinimumLength = 6, ErrorMessage = "密碼只能是6到12位")] public string Pwd { get; set; } /// <summary> /// 確認密碼 /// </summary> [Compare("Pwd", ErrorMessage = "兩次密碼輸入的不一致")] public string RPwd { get; set; } public string AAA { get; set; } /// <summary> /// 備注 /// </summary> [StringLength(200, ErrorMessage = "備注不能超過200字")] public string Remark { get; set; } /// <summary> /// 職員編號 /// </summary> [Required] //Swagger 字段后有一個*表示必填,實際上在傳參的時候不填會有默認值0,這個沒有起到實際意義上的驗證效果 [Range(1, int.MaxValue, ErrorMessage = "職員編號不能為空")] //適用於自增長Id public int EmpId { get; set; } /// <summary> /// 備注2 /// </summary> [StringLength(200, MinimumLength = 1, ErrorMessage = "備注2只能是1至200字")] //可以為null,不能為"" public string Remark2 { get; set; } /// <summary> /// 年齡 /// </summary> [Range(18, 60, ErrorMessage = "年齡只能是18到60歲")] //可null類型,可以為null public int? Age { get; set; } /// <summary> /// 價格 /// </summary> [Range(9.99, 99.99, ErrorMessage = "價格只能是9.99至99.99")] public double Price { get; set; } /// <summary> /// 生日 /// </summary> [Range(typeof(DateTime), "2021-03-02", "2021-04-02", ErrorMessage = "日期只能是3月2號到4月2號")] //2021-04-02 00:00:01 不符合 public DateTime Birthday { get; set; } } }
基礎屬性【RegularExpression】
using System.ComponentModel.DataAnnotations; namespace Test.Application.Employee.Dto { /// <summary> /// 常工規則 /// 1、手機號碼 /// 通用校驗規則:^1[3456789]\d{9}$ /// 詳細手機號校驗規則:^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$ /// 驗證手機號和固定電話:^((0\d{2,3}-\d{7,8})|(1[34578]\d{9}))$ /// 2、郵箱格式 /// [\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])? /// 3、用戶名校驗 /// 6-16位的包含大小寫字母、數字、特殊符號- _ 的用戶名:^[a-zA-Z0-9_-]{6,16}$ /// 6-20位字母和數字組合:^(?![0-9]*$)(?![a-zA-Z]*$)[a-zA-Z0-9]{6,20}$ /// 4、密碼強度校驗 /// 密碼強度正則,最少6位,包括至少1個大寫字母,1個小寫字母,1個數字,1個特殊字符:^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$ /// 請輸入6-20位英文字母、數字或者符號(除空格),且字母、數字和標點符號至少包含兩種:^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$)([^\u4e00-\u9fa5\s]){6,20}$ /// 5、整數校驗 /// 正整數正則:^\d+$ /// 負整數正則:^-\d+$ /// 整數正則:^-?\d+$ /// 6、身份證驗證 /// (^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$) /// 7、合法url校驗 /// ^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$ /// 8、驗證輸入內容是否包含英文數字及下划線 /// ^[_a-zA-Z0-9]+$ /// 9、驗證是否兩位小數 /// (^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$) /// 10、中文校驗 /// ^[\u0391-\uFFE5A-Za-z]+$ /// 11、純數字校驗 /// ^\d+$|^\d+[.]?\d+$ /// 12、最多一位小數 /// ^[0-9]+([.]{1}[0-9]{1})?$ /// 13、ip地址校驗 /// ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ /// 14、包含中文的校驗 /// [\u4e00-\u9fa5] /// 15、內容只能由英文、數字、下划線組成 /// ^\w+$ /// 16、內容只能包含英文字母和數字 /// ^[a-z0-9]+$ /// 17、固定電話 /// ^((0\d{2,5}-)|0\d2,50\d2,5)?\d{7,8}(-\d{3,4})?$ /// </summary> public class ModifyEmployeeDto { /// <summary> /// 郵箱 /// </summary> [RegularExpression(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4})$", ErrorMessage = "郵箱格式不正確")] public string Email { get; set; } /// <summary> /// 身份證 /// </summary> [RegularExpression(@"^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$", ErrorMessage = "錯誤")] public string IDCard { get; set; } } }
基礎屬性【Remote】【沒有查到相關資料,有知道的小伙伴請在評論區留下代碼】
自定義驗證
在XXX.Service項目中新建文件夾【Base/Validation】新建類:EnumCheckAttribute
using System; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; namespace Test.Application.Base.Validation { /// <summary> /// 自定義驗證 /// 驗證是否是有效的枚舉值 /// </summary> public class EnumCheckAttribute : ValidationAttribute { /// <summary> /// 驗證的枚舉類Type /// </summary> public Type TypeClass { get; set; } /// <summary> /// 枚舉范圍外的鍵,如有更好的方案請留言 /// </summary> public int OtherKey { get; set; } = int.MinValue; /// <summary> /// 枚舉范圍外的值 /// </summary> public string OtherValue { get; set; } public override bool IsValid(object value) { string enumValue = Enum.GetName(TypeClass, value); if (enumValue == null) { if (OtherKey == Convert.ToInt32(value)) { return true; } return false; } return true; } /// <summary> /// 提示中,添加枚舉的鍵值對,如有更好的方案請留言 /// </summary> /// <param name="name"></param> /// <returns></returns> public override string FormatErrorMessage(string name) { return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, new object[] { EnumToJson() }); } /// <summary> /// 如有更好的方案請留言 /// </summary> /// <returns></returns> private string EnumToJson() { if (!TypeClass.IsEnum) throw new InvalidOperationException("enum expected"); var results = Enum.GetValues(TypeClass).Cast<object>().ToDictionary(enumValue => (int)enumValue, enumValue => enumValue.ToString()); //if (OtherKey != int.MinValue) //{ // results.Add(OtherKey, OtherValue); //} //return string.Format("{0}", JsonConvert.SerializeObject(results)).Replace("\"", ""); string result = "{"; if (OtherKey != int.MinValue) { result += OtherValue + ":" + OtherKey + ","; } foreach (var key in results.Keys) { result += results[key] + ":" + key + ","; } result = result.Remove(result.Length - 1); result += "}"; return result; } } }
使用
using Test.Application.Base.Validation; using Test.Model; namespace Test.Application.Employee.Dto { public class QueryEmployeeDto { /// <summary> /// 性別 /// </summary> [EnumCheck(TypeClass = typeof(Genders), OtherKey = -1, OtherValue = "全部", ErrorMessage = "性別無效,范圍值為:{0}")] public int Gender { get; set; } } }