Change
在无知的时候,我们常常会笑他人的肤浅。但终会明白,肤浅的是自己。

导航

 

    最近在做一个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 { getset; }

          
/// <summary>
          
/// 商品名称
          
/// </summary>
          public string CommodityName { getset; }

          
/// <summary>
          
/// 商品数量
          
/// </summary>
          public string CommodityAmount { getset; }

          
/// <summary>
          
/// 商品重量
          
/// </summary>
          public string CommodityWeight { getset; }

          
/// <summary>
          
/// 商品价格
          
/// </summary>
          public string CommodityValue { getset; }

          
/// <summary>
          
/// 希望到货时间
          
/// </summary>
          public string HopeArriveTime { getset; }

          
/// <summary>
          
/// 结算方式
          
/// </summary>
          public string PayMent { getset;}

          
/// <summary>
          
/// 备注
          
/// </summary>
          public string Remark { getset; }
     }

 

 

      可能有的朋友会说,你这也忒不专业了,所有类型都是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 { getset; }

          
/// <summary>
          
/// 商品名称
          
/// </summary>
          [Validate(ValidateType.IsEmpty|ValidateType.MaxLength,MaxLength = 50)]
          
public string CommodityName { getset; }

          
/// <summary>
          
/// 商品数量
          
/// </summary>
          [Validate(ValidateType.IsEmpty|ValidateType.IsNumber)]
          
public string CommodityAmount { getset; }

          
/// <summary>
          
/// 商品重量
          
/// </summary>
          [Validate(ValidateType.IsEmpty | ValidateType.IsDecimal)]
          
public string CommodityWeight { getset; }

          
/// <summary>
          
/// 商品价格
          
/// </summary>
          [Validate(ValidateType.IsEmpty | ValidateType.IsDecimal)]
          
public string CommodityValue { getset; }

          
/// <summary>
          
/// 希望到货时间
          
/// </summary>
          [Validate(ValidateType.IsEmpty | ValidateType.IsDateTime)]
          
public string HopeArriveTime { getset; }

          
/// <summary>
          
/// 结算方式
          
/// </summary>
          [Validate(ValidateType.IsEmpty | ValidateType.IsInCustomArray,CustomArray = new string[]{"现结","到付","月结"})]
          
public string PayMent { getset;}

          
/// <summary>
          
/// 备注
          
/// </summary>
          [Validate(ValidateType.MaxLength,MaxLength = 256)]
          
public string Remark { getset; }
     } 

 

 

 

       由于我们的枚举实用了位标记(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 < 1break;
                                        
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 < 1break;
                                        
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 < 1break;
                                        
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 < 1break;
                                        
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 < 1break;
                                        
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 < 1break;
                                        
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 < 1break;
                                        
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 < 1break;
                                        
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 < 1break;
                                        
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 < 1goto case ValidateType.IsEmpty;
                                        
goto case ValidateType.MinLength;
                                   
//验证元素是否为空且符合指定的最大长度
                                   case ValidateType.IsEmpty | ValidateType.MaxLength:
                                        
if (null == value || value.ToString().Length < 1goto case ValidateType.IsEmpty;
                                        
goto case ValidateType.MaxLength;
                                   
//验证元素是否为空且符合指定的长度范围
                                   case ValidateType.IsEmpty | ValidateType.MinLength | ValidateType.MaxLength:
                                        
if (null == value || value.ToString().Length < 1goto case ValidateType.IsEmpty;
                                        
goto case ValidateType.MinLength | ValidateType.MaxLength;
                                   
//验证元素是否为空且值为数值型
                                   case ValidateType.IsEmpty | ValidateType.IsNumber:
                                        
if (null == value || value.ToString().Length < 1goto case ValidateType.IsEmpty;
                                        
goto case ValidateType.IsNumber;
                                   
//验证元素是否为空且值为浮点型
                                   case ValidateType.IsEmpty | ValidateType.IsDecimal:
                                        
if (null == value || value.ToString().Length < 1goto case ValidateType.IsEmpty;
                                        
goto case ValidateType.IsDecimal;
                                   
//验证元素是否为空且值为时间类型
                                   case ValidateType.IsEmpty | ValidateType.IsDateTime:
                                        
if (null == value || value.ToString().Length < 1goto case ValidateType.IsEmpty;
                                        
goto case ValidateType.IsDateTime;
                                   
//验证元素是否为空且值在指定的数据源中
                                   case ValidateType.IsEmpty | ValidateType.IsInCustomArray:
                                        
if (null == value || value.ToString().Length < 1goto case ValidateType.IsEmpty;
                                        
goto case ValidateType.IsInCustomArray;
                                   
//验证元素是否为空且值为固定电话号码格式
                                   case ValidateType.IsEmpty | ValidateType.IsTelphone:
                                        
if (null == value || value.ToString().Length < 1goto case ValidateType.IsEmpty;
                                        
goto case ValidateType.IsTelphone;
                                   
//验证元素是否为空且值为手机号码格式
                                   case ValidateType.IsEmpty | ValidateType.IsMobile:
                                        
if (null == value || value.ToString().Length < 1goto 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上开发,是故后面的实现代码有些冗长

 

    希望大家多提意见或建议,共同学习,共同进步! 

 

 

 

posted on 2010-08-24 00:07  Funeral  阅读(3066)  评论(28编辑  收藏  举报