我们知道DataAnnotations是一个通用的数据模型元数据定义框架,其中最主要的部分是验证框架的定义。DataAnnotations可用户.NET平台的任何应用框架,但我们的项目中都是借助MVC来使用DataAnnotations。在MVC框架中,还对DataAnnotations进行了很多的扩展和适配:比如需要根据定义的DataAnnotations,生成客户端的验证;在Controller模型中绑定模型对数据进行有效性验证等等。我们的数据模型如果都是通过MVC入口,用户输入有的有效性验证的工作都可以交给MVC框架和DataAnnotations来完成。在我们的实践中,这样确实给我们带来了很大的的方便。
但是,当我们的数据入口不是走MVC通道,而是通过其它的入口(WebService,或其它服务)进来,这时我们就很难利用现有的MVC验证框架,我们可以模拟很多请求Context,并最终模拟ControllerContext,但是这样的工作实在太麻烦了。既然使用了DataAnnotations的验证标签定义,最好的方案还是复用这些标签,使用同一套验证机制。翻开DataAnnotations源码,希望能找到一个独立验证的辅助方法,很遗憾,并没有找到。
还是只能自己来实现这个功能,在没有下手之前好像还是有点麻烦的感觉(好像这是我们一贯的毛病,总是把很多事情都想的很难的样子,而且很多时候心里总会有点抵触,这点一定要在工作中好好改进)。不过,一切还是很简单的,主要还是要归功于TypeDescriptor。TypeDescriptor为我们准备好了类型相关的所有元信息,而且还可以通过它得到属性的PropertyDescriptor,这一下就简化了太多的工作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public
class
ModelValidationError
{
public
string
FieldName {
get
;
set
; }
public
string
Message {
get
;
set
; }
}
public
static
class
DataAnnotationHelper
{
public
static
IEnumerable<ModelValidationError> IsValid<T>(
this
T o)
{
var descriptor = GetTypeDescriptor(
typeof
(T));
foreach
(PropertyDescriptor propertyDescriptor
in
descriptor.GetProperties())
{
foreach
(var validationAttribute
in
propertyDescriptor.Attributes.OfType<ValidationAttribute>())
{
if
(!validationAttribute.IsValid(propertyDescriptor.GetValue(o)))
{
yield
return
new
ModelValidationError() { FieldName = propertyDescriptor.Name, Message = validationAttribute.FormatErrorMessage(propertyDescriptor.Name) };
}
}
}
}
private
static
ICustomTypeDescriptor GetTypeDescriptor(Type type)
{
return
new
AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type);
}
}
|
很简单,只需要几行代码就可以完成基于DataAnnotations的独立验证。值得注意的是,上面使用AssociatedMetadataTypeTypeDescriptionProvider来获取TypeDescriptor,是希望兼容MetadataType的方式注入元数据。有了上面的辅助方法,我们验证实体的有效性就变得非常轻松:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public
class
Model1
{
[Required]
public
string
Name {
get
;
set
; }
[Range(1, 100)]
public
int
Age {
get
;
set
; }
}
class
Program
{
static
void
Main(
string
[] args)
{
Model1 model =
new
Model1();
foreach
(var item
in
model.IsValid())
{
Console.WriteLine(
"FieldName:{0} Error Message:{1}"
, item.FieldName, item.Message);
}
Console.ReadLine();
}
}
|
非常简单的扩展,非常完美的解决了我的问题。希望也对你有所帮助。