.net5 - 創建Web.Api項目(四)DataAnnotations實現數據驗證


命名空間

 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; }
    }
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM