首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

善用 Attribute 實現實體類別驗證框架

     編輯:關於.NET

背景動機

處理 XML 時常反序列化為實體物件操作。傳統驗證寫法充滿 if-else 判斷,造成語法噪音。利用 C# Attribute 可建立聲明式驗證框架,大幅簡化程式碼。

驗證類型列舉

[Flags]
public enum ValidateType
{
    IsEmpty = 0x0001,
    MinLength = 0x0002,
    MaxLength = 0x0004,
    IsNumber = 0x0008,
    IsDateTime = 0x0010,
    IsDecimal = 0x0020,
    IsInCustomArray = 0x0040,
    IsTelphone = 0x0080,
    IsMobile = 0x0100
}

自訂驗證屬性

[AttributeUsage(AttributeTargets.All)]
public class ValidateAttribute : Attribute
{
    public ValidateType ValidateType { get; private set; }
    public int MinLength { get; set; }
    public int MaxLength { get; set; }
    public string[] CustomArray { get; set; }

    public ValidateAttribute(ValidateType validateType)
    {
        this.ValidateType = validateType;
    }
}

套用至實體類別

public class OrderRequest
{
    [Validate(ValidateType.IsEmpty)]
    public string OrderNo { get; set; }

    [Validate(ValidateType.IsEmpty | ValidateType.MaxLength, MaxLength = 50)]
    public string CommodityName { get; set; }

    [Validate(ValidateType.IsEmpty | ValidateType.IsNumber)]
    public string CommodityAmount { get; set; }

    [Validate(ValidateType.IsEmpty | ValidateType.IsDecimal)]
    public string CommodityWeight { get; set; }

    [Validate(ValidateType.IsEmpty | ValidateType.IsDecimal)]
    public string CommodityValue { get; set; }

    [Validate(ValidateType.IsEmpty | ValidateType.IsDateTime)]
    public string HopeArriveTime { get; set; }

    [Validate(ValidateType.IsEmpty | ValidateType.IsInCustomArray, CustomArray = new[] { "現結", "到付", "月結" })]
    public string PayMent { get; set; }

    [Validate(ValidateType.MaxLength, MaxLength = 256)]
    public string Remark { get; set; }
}

驗證引擎實作

透過反射掃描屬性上的 ValidateAttribute,依 ValidateType 執行對應邏輯(正則表達式、長度檢查、自訂陣列比對等),回傳第一個錯誤訊息或 String.Empty 表示通過。

public static string GetValidateResult(object entityObject)
{
    if (entityObject == null) throw new ArgumentNullException("entityObject");
    Type type = entityObject.GetType();
    PropertyInfo[] properties = type.GetProperties();
    string validateResult = string.Empty;

    foreach (PropertyInfo prop in properties)
    {
        object[] attrs = prop.GetCustomAttributes(typeof(ValidateAttribute), true);
        if (attrs.Length == 0) continue;

        object value = prop.GetValue(entityObject, null);
        foreach (ValidateAttribute attr in attrs)
        {
            switch (attr.ValidateType)
            {
                case ValidateType.IsEmpty:
                    if (value == null || value.ToString().Length == 0)
                        validateResult = string.Format("元素 {0} 不能為空", prop.Name);
                    break;
                case ValidateType.MaxLength:
                    if (value != null && value.ToString().Length > attr.MaxLength)
                        validateResult = string.Format("元素 {0} 長度不能大於 {1}", prop.Name, attr.MaxLength);
                    break;
                case ValidateType.IsNumber:
                    if (value != null && !Regex.IsMatch(value.ToString(), @"^\d+$"))
                        validateResult = string.Format("元素 {0} 必須為數值", prop.Name);
                    break;
                case ValidateType.IsDecimal:
                    if (value != null && !Regex.IsMatch(value.ToString(), @"^\d+[.]?\d+$"))
                        validateResult = string.Format("元素 {0} 必須為金額格式", prop.Name);
                    break;
                case ValidateType.IsDateTime:
                    if (value != null && !Regex.IsMatch(value.ToString(), @"(\d{2,4})[-/]?([0]?[1-9]|[1][12])[-/]?([0][1-9]|[12]\d|[3][01])\s*([01]\d|[2][0-4])?[:]?([012345]?\d)?[:]?([012345]?\d)?"))
                        validateResult = string.Format("元素 {0} 日期格式錯誤", prop.Name);
                    break;
                case ValidateType.IsInCustomArray:
                    if (attr.CustomArray == null || attr.CustomArray.Length == 0)
                        validateResult = string.Format("系統錯誤:元素 {0} 自訂資料來源為空", prop.Name);
                    else if (!Array.Exists(attr.CustomArray, s => s == value.ToString()))
                        validateResult = string.Format("元素 {0} 值必須為 {1} 之一", prop.Name, string.Join(",", attr.CustomArray));
                    break;
                // 組合旗標處理略...
            }
            if (!string.IsNullOrEmpty(validateResult)) break;
        }
        if (!string.IsNullOrEmpty(validateResult)) break;
    }
    return validateResult;
}

使用方式

OrderRequest order = XmlAntiSerialization.Deserialize(typeof(OrderRequest), xmlString) as OrderRequest;
string msg = AttributeHandle.GetValidateResult(order);
if (!string.IsNullOrEmpty(msg)) return msg;
// 繼續業務邏輯...

一行程式碼完成整個實體驗證,頁面清爽無比。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved