利用特性(Attribute)对实体类进行验证

    最近在做一个EDI项目,主要流程就是客户以HttpPost或Webservice的方式向我们公司下订单,订单内容是以XML格式表示,我这边需要做的操作是:

一: 验证请求是否合法(双方密钥)

二: 验证请求内容是否正确且符合一定的格式要求

三:   对订单进行处理 

     验证用户的请求是否合法以及对订单的处理就不说了,我今天主要说的是一种优雅、美观、清爽、干净的验证方式

     对于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....

  大功告成,整个页面清爽无比

 

原文地址:http://www.cnblogs.com/funeral/archive/2010/08/24/Attribute_Validate_EntityObject.html

你可能感兴趣的:(attribute)