程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 利用特性(Attribute)對實體類進行驗證

利用特性(Attribute)對實體類進行驗證

編輯:關於.NET

對於XML的內容,我這邊的處理方式是將它反序列化成實體對象,畢竟操作一 個實體對象比一大堆的XPath強多了。

.net framework自帶的XML序列化和反序列化類 System.Xml.Serialization.XmlSerializer由於內部實現過於復雜,導致性能不 佳。我這邊自己實現了一個XML反序列化類,性能雖好但比較有針對性,所以今 天還是以.net framework自帶的XML反序列化類作為示范。

比如說一個XML的內容是這樣:

<? xml version = "1.0" encoding = "utf-8"?>
<OrderRequest>
<!-- 訂單號 -->
<OrderNo>T-1234567</OrderNo>
<!-- 商品名稱 -->
<CommodityName>筆記本電腦</CommodityName>
<!-- 商品數量 -->
<CommodityAmount>1</CommodityAmount>
<!-- 商品重量 單位:KG -->
<CommodityWeight>5.27</CommodityWeight>
<!-- 商品價格 -->
<CommodityValue>13999.00</CommodityValue>
<!-- 希望到達時間 -->
<HopeArriveTime>2010-09-01 00:00:00</HopeArriveTime>
<!-- 結算方式 只能為現結、到付和月結三種 -->
<PayMent>現結</PayMent>
<!-- 備注 -->
<Remark>小心輕放</Remark>
</OrderRequest>

當然,正常的訂單不會只有這麼點內容,下面我們要為它設計一個實體 類:

/// <summary>
      /// 訂單實體類
      /// </summary>
      public class OrderRequest
      {
           /// <summary>
           /// 訂單號
           /// </summary>
           public string OrderNo { get; set; }
           /// <summary>
           /// 商品名稱
           /// </summary>
           public string CommodityName { get; set;  }
           /// <summary>
           /// 商品數量
           /// </summary>
           public string CommodityAmount { get; set;  }
           /// <summary>
           /// 商品重量
           /// </summary>
           public string CommodityWeight { get; set;  }
           /// <summary>
           /// 商品價格
           /// </summary>
           public string CommodityValue { get; set;  }
           /// <summary>
           /// 希望到貨時間
           /// </summary>
           public string HopeArriveTime { get; set;  }
           /// <summary>
           /// 結算方式
           /// </summary>
           public string PayMent { get; set;}
           /// <summary>
           /// 備注
           /// </summary>
           public string Remark { get; set; }
      }

可能有的朋友會說,你這也忒不專業了,所有類型都是string。別著急,我 想說的重點是驗證方式,類型轉換之類的先放一邊吧。

然後利用微軟自帶的XML反序列化類將XML反序列成對象,下面是反序列化的 方法:

using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
     /// <summary>
     /// 反序列化類
     /// </summary>
     public class XmlAntiSerialization
     {
         /// <summary>
         /// 反序列化
         /// </summary>
         /// <param name="type">實體對象類型 </param>
         /// <param name="xml">XML字符串 </param>
         /// <returns></returns>
         public static object Deserialize(Type type,  string xml)
         {
              try
              {
                   using (StringReader sr =  new StringReader(xml))
                   {
                        XmlSerializer xmldes  = new XmlSerializer(type);
                        return  xmldes.Deserialize(sr);
                   }
              }
              catch(Exception ex)
              {
                   throw ex;
              }
         }
      }

只需如此調用即可將XML內容反序列化:

OrderRequest orderRequest =  XmlAntiSerialization.Deserialize(typeof(OrderRequest),  this.XmlString) as OrderRequest;

傳統的驗證方式大概是這樣的:

if (string.IsNullOrEmpty(orderRequest.OrderNo))
                 return "訂單號不能為空";
      if(string.IsNullOrEmpty(orderRequest.CommodityAmount) ||  !System.Text.RegularExpressions.Regex.IsMatch (orderRequest.CommodityAmount,@"^\d+$"))
                 return "商品數量不能為空且只能為數 字";
      if (string.IsNullOrEmpty(orderRequest.PayMent) ||  (orderRequest.PayMent != "現結" && orderRequest.PayMent  != "到付" && orderRequest.PayMent != "月結"))
                 return "結算方式不能為空,且必須為 現結、到付或月結的一種";

如此這般一大堆,想保證頁面的清爽是不大可能了,按老趙的話說就是一股 語法噪音。但C sharp 這把鋒利的刃還給我們提供了更趁手的武器:特性 (Attribute)

好吧,讓我們先定義一個驗證方式的枚舉:

/// <summary>
      /// 驗證類型
      /// </summary>
      [Flags]
      public enum ValidateType
      {
           /// <summary>
           /// 字段或屬性是否為空字串
           /// </summary>
           IsEmpty = 0x0001,
           /// <summary>
           /// 字段或屬性的最小長度
           /// </summary>
           MinLength = 0x0002,
           /// <summary>
           /// 字段或屬性的最大長度
           /// </summary>
           MaxLength = 0x0004,
           /// <summary>
           /// 字段或屬性的值是否為數值型
           /// </summary>
           IsNumber = 0x0008,
           /// <summary>
           /// 字段或屬性的值是否為時間類型
           /// </summary>
           IsDateTime = 0x0010,
           /// <summary>
           /// 字段或屬性的值是否為正確的浮點類型
           /// </summary>
           IsDecimal = 0x0020,
           /// <summary>
           /// 字段或屬性的值是否包含在指定的數據源數組中
           /// </summary>
           IsInCustomArray = 0x0040,
           /// <summary>
           /// 字段或屬性的值是否為固定電話號碼格式
           /// </summary>
           IsTelphone = 0x0080,
           /// <summary>
           /// 字段或屬性的值是否為手機號碼格式
           /// </summary>
           IsMobile = 0x0100
      }

再實現一個自定義的特性類:

/// <summary>
      /// 為元素添加驗證信息的特性類
      /// </summary>
      [AttributeUsage(AttributeTargets.All)]
      public class ValidateAttribute : Attribute
      {
           /// <summary>
           /// 驗證類型
           /// </summary>
           private ValidateType _validateType;
           /// <summary>
           /// 最小長度
           /// </summary>
           private int _minLength;
           /// <summary>
           /// 最大長度
           /// </summary>
           private int _maxLength;
           /// <summary>
           /// 自定義數據源 
           /// </summary>
           private string[] _customArray;

           /// <summary>
           /// 驗證類型
           /// </summary>
           public ValidateType ValidateType
           {
                get { return this._validateType;  }
           }
           /// <summary>
           /// 最小長度
           /// </summary>
           public int MinLength
           {
                get { return this._minLength; }
                set { this._minLength = value;  }
           }
           /// <summary>
           /// 最大長度
           /// </summary>
           public int MaxLength
           {
                get { return this._maxLength; }
                set { this._maxLength = value;  }
           }
           /// <summary>
           /// 自定義數據源
           /// </summary>
           public string[] CustomArray
           {
                get { return this._customArray;  }
                set { this._customArray = value;  }
           }

           /// <summary>
           /// 指定采取何種驗證方式來驗證元素的有效性
           /// </summary>
           /// <param  name="validateType"></param>
           public ValidateAttribute(ValidateType  validateType)
           {
                this._validateType =  validateType;
           }
      }

下面我們就可以在實體類的屬性上增加特性驗證:

public class OrderRequest
      {
           /// <summary>
           /// 訂單號
           /// </summary>
           [Validate(ValidateType.IsEmpty)]
           public string OrderNo { get; set; }
           /// <summary>
           /// 商品名稱
           /// </summary>
           [Validate (ValidateType.IsEmpty|ValidateType.MaxLength,MaxLength = 50)]
           public string CommodityName { get; set;  }
           /// <summary>
           /// 商品數量
           /// </summary>
           [Validate (ValidateType.IsEmpty|ValidateType.IsNumber)]
           public string CommodityAmount { get; set;  }
           /// <summary>
           /// 商品重量
           /// </summary>
           [Validate(ValidateType.IsEmpty |  ValidateType.IsDecimal)]
           public string CommodityWeight { get; set;  }
           /// <summary>
           /// 商品價格
           /// </summary>
           [Validate(ValidateType.IsEmpty |  ValidateType.IsDecimal)]
           public string CommodityValue { get; set;  }
           /// <summary>
           /// 希望到貨時間
           /// </summary>
           [Validate(ValidateType.IsEmpty |  ValidateType.IsDateTime)]
           public string HopeArriveTime { get; set;  }
           /// <summary>
           /// 結算方式
           /// </summary>
           [Validate(ValidateType.IsEmpty |  ValidateType.IsInCustomArray,CustomArray = new string[]{"現結","到 付","月結"})]
           public string PayMent { get; set;}
           /// <summary>
           /// 備注
           /// </summary>
           [Validate(ValidateType.MaxLength,MaxLength =  256)]
           public string Remark { get; set; }
      }

由於我們的枚舉實用了位標記(FlagsAttribute),所以我們可以對某個元素 使用多種驗證方式。下面就是驗證的實現:

/// <summary>
           /// 驗證實體對象的所有帶驗證特性的元素   並返回驗證結果  如果返回結果為String.Empty 則說明元素符合驗證要求
           /// </summary>
           /// <param name="entityObject">實體對象 </param>
           /// <returns></returns>
           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 property in  properties)
                {
                     //獲取驗證特性
                     object[] validateContent  = property.GetCustomAttributes(typeof(ValidateAttribute), true);
                     if (validateContent !=  null)
                     {
                          //獲取屬性的值
                          object value =  property.GetValue(entityObject, null);
                          foreach  (ValidateAttribute validateAttribute in validateContent)
                          {
                               switch  (validateAttribute.ValidateType)
                               {
                                     //驗證元素是否為空字串
                                     case ValidateType.IsEmpty:
                                          if (null == value || value.ToString().Length <  1)
                                               validateResult = string.Format("元素 {0} 不 能為空", property.Name);
                                          break;
                                     //驗證元素的長度是否小於指定最小長度
                                     case ValidateType.MinLength:
                                          if (null == value || value.ToString().Length <  1) break;
                                          if (value.ToString().Length <  validateAttribute.MinLength)
                                               validateResult = string.Format("元素 {0} 的 長度不能小於 {1}", property.Name, validateAttribute.MinLength);
                                          break;
                                     //驗證元素的長度是否大於指定最大長度
                                     case ValidateType.MaxLength:
                                          if (null == value || value.ToString().Length <  1) break;
                                          if (value.ToString().Length >  validateAttribute.MaxLength)
                                               validateResult = string.Format("元素 {0} 的 長度不能大於{1}", property.Name, validateAttribute.MaxLength);
                                          break;
                                     //驗證元素的長度是否符合指定的最大長度和最小長度的范圍
                                     case ValidateType.MinLength | ValidateType.MaxLength:
                                          if (null == value || value.ToString().Length <  1) break;
                                          if (value.ToString().Length >  validateAttribute.MaxLength || value.ToString().Length <  validateAttribute.MinLength)
                                               validateResult = string.Format("元素 {0} 不 符合指定的最小長度和最大長度的范圍,應該在 {1} 與 {2} 之間",  property.Name, validateAttribute.MinLength,  validateAttribute.MaxLength);
                                          break;
                                     //驗證元素的值是否為值類型
                                     case ValidateType.IsNumber:
                                          if (null == value || value.ToString().Length <  1) break;
                                          if (!System.Text.RegularExpressions.Regex.IsMatch (value.ToString(), @"^\d+$"))
                                               validateResult = string.Format("元素 {0} 的 值不是值類型", property.Name);
                                          break;
                                     //驗證元素的值是否為正確的時間格式
                                     case ValidateType.IsDateTime:
                                          if (null == value || value.ToString().Length <  1) break;
                                          if (!System.Text.RegularExpressions.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} 不 是正確的時間格式", property.Name);
                                          break;
                                     //驗證元素的值是否為正確的浮點格式
                                     case ValidateType.IsDecimal:
                                          if (null == value || value.ToString().Length <  1) break;
                                          if (!System.Text.RegularExpressions.Regex.IsMatch (value.ToString(), @"^\d+[.]?\d+$"))
                                               validateResult = string.Format("元素 {0} 不 是正確的金額格式", property.Name);
                                          break;
                                     //驗證元素的值是否在指定的數據源中
                                     case ValidateType.IsInCustomArray:
                                          if (null == value || value.ToString().Length <  1) break;
                                          if (null == validateAttribute.CustomArray ||  validateAttribute.CustomArray.Length < 1)
                                               validateResult = string.Format("系統內部錯誤 :元素 {0} 指定的數據源為空或沒有數據", property.Name);
                                          bool isHas = Array.Exists<string> (validateAttribute.CustomArray, delegate(string str)
                                          {
                                               return str == value.ToString();
                                          }
                                          );
                                          if (!isHas)
                                               validateResult = string.Format("元素 {0} 的 值設定不正確 , 應該為 {1} 中的一種", property.Name, string.Join (",", validateAttribute.CustomArray));
                                          break;
                                     //驗證元素的值是否為固定電話號碼格式
                                     case ValidateType.IsTelphone:
                                          if (null == value || value.ToString().Length <  1) break;
                                          if (!System.Text.RegularExpressions.Regex.IsMatch (value.ToString(), @"^(\d{3,4}-)?\d{6,8}$"))
                                               validateResult = string.Format("元素 {0} 不 是正確的固定電話號碼格式", property.Name);
                                          break;
                                     //驗證元素的值是否為手機號碼格式
                                     case ValidateType.IsMobile:
                                          if (null == value || value.ToString().Length <  1) break;
                                          if (!System.Text.RegularExpressions.Regex.IsMatch (value.ToString(), @"^[1]+[3,5]+\d{9}$"))
                                               validateResult = string.Format("元素 {0} 不 是正確的手機號碼格式", property.Name);
                                          break;
                                     //驗證元素是否為空且符合指定的最小長度
                                     case ValidateType.IsEmpty | ValidateType.MinLength:
                                          if (null == value || value.ToString().Length <  1) goto case ValidateType.IsEmpty;
                                          goto case ValidateType.MinLength;
                                     //驗證元素是否為空且符合指定的最大長度
                                     case ValidateType.IsEmpty | ValidateType.MaxLength:
                                          if (null == value || value.ToString().Length <  1) goto case ValidateType.IsEmpty;
                                          goto case ValidateType.MaxLength;
                                     //驗證元素是否為空且符合指定的長度范圍
                                     case ValidateType.IsEmpty | ValidateType.MinLength |  ValidateType.MaxLength:
                                          if (null == value || value.ToString().Length <  1) goto case ValidateType.IsEmpty;
                                          goto case ValidateType.MinLength |  ValidateType.MaxLength;
                                     //驗證元素是否為空且值為數值型
                                     case ValidateType.IsEmpty | ValidateType.IsNumber:
                                          if (null == value || value.ToString().Length <  1) goto case ValidateType.IsEmpty;
                                          goto case ValidateType.IsNumber;
                                     //驗證元素是否為空且值為浮點型
                                     case ValidateType.IsEmpty | ValidateType.IsDecimal:
                                          if (null == value || value.ToString().Length <  1) goto case ValidateType.IsEmpty;
                                          goto case ValidateType.IsDecimal;
                                     //驗證元素是否為空且值為時間類型
                                     case ValidateType.IsEmpty | ValidateType.IsDateTime:
                                          if (null == value || value.ToString().Length <  1) goto case ValidateType.IsEmpty;
                                          goto case ValidateType.IsDateTime;
                                     //驗證元素是否為空且值在指定的數據源中
                                     case ValidateType.IsEmpty | ValidateType.IsInCustomArray:
                                          if (null == value || value.ToString().Length <  1) goto case ValidateType.IsEmpty;
                                          goto case ValidateType.IsInCustomArray;
                                     //驗證元素是否為空且值為固定電話號碼格式
                                     case ValidateType.IsEmpty | ValidateType.IsTelphone:
                                          if (null == value || value.ToString().Length <  1) goto case ValidateType.IsEmpty;
                                          goto case ValidateType.IsTelphone;
                                     //驗證元素是否為空且值為手機號碼格式
                                     case ValidateType.IsEmpty | ValidateType.IsMobile:
                                          if (null == value || value.ToString().Length <  1) goto case ValidateType.IsEmpty;
                                          goto case ValidateType.IsMobile;
                                     default:
                                          break;
                               }
                          }
                     }
                     if (!string.IsNullOrEmpty (validateResult))
                          break;
                }
                return validateResult;
           }

最後,我們只需調用這麼一句代碼,就可以實現對整個實體類的元素的驗證 :

//驗證訂單
string checkMessage = AttributeHandle.GetValidateResult (orderRequest);
if(!string.IsNullOrEmpty(checkMessage))
    return checkMessage;
//do something....

大功告成,整個頁面清爽無比

附:由於公司的一些原因,我只能在基於.net framework2.0的VS2005上開發 ,是故後面的實現代碼有些冗長

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved