最近在做一个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