ASP.NET MVC以ModelValidator为核心的Model验证体系: ModelValidator2012-09-21 cnblogs Artech旨在为目标Action方法的执行绑定输入参数的Model绑定过程伴随着对Model的验证。借助相应的验证特性,我们可以直接以声明的方式在Model类型上定义验证规则,这些规则将会作为Model元数据的一部分。具体在Model绑定过程中,ModelBinder通过ValueProvider为Model对象的某个属性提供相应属性值之后,会根据定义在基于该属性的Model元数据的验证规则实施验证。ASP.NET MVC的整个Model验证系统以组件ModelValidator为核心,或者说Model对象的验证最终通过某个ModelValidator对象来完成,所以我们有必要先来认识一下ModelValidator以及背后的提供机制。一、ModelValidator在ASP.NET MVC应用编程接口中,所有的ModelValidator都直接或者间接地继承自抽象类型ModelValidator。如下面的代码片断所示,ModelValidator具有一个布尔类型的只读属性IsRequired,表示该ModelValidator是否是对目标数据进行必要性的验证,默认返回False。GetClientValidationRules返回一个元素类型为ModelClientValidationRule的集合。ModelClientValidationRule是对客户端验证规则的封装,我们会在进行客户端验证时对其进行详细介绍。
 1: public abstract class ModelValidator
 2: {
 3: //其他成员
 4: public virtual IEnumerable<ModelClientValidationRule> GetClientValidationRules();
 5: public abstract IEnumerable<ModelValidationResult> Validate(object container);
 6:
 7: public virtual bool IsRequired { get; }
 8: }
真正对目标数据实施验证是通过调用Validate方法来完成的,而该方法的输入参数container表示的正式被验证的对象。该Validate返回一个表示验证结果的元素类型为ModelValidationResult的集合,该类型的定义如下所示。
 1: public class ModelValidationResult
 2: {
 3: public ModelValidationResult();
 4: 
 5: public string MemberName { get; set; }
 6: public string Message { get; set; }
 7: }
ModelValidationResult具有两个字符串类型的属性MemberName和Message,前者代表被验证数据成员的名称,后者表示错误消息。一般来说,当它们用于验证某个复杂类型对象的时候,针对于类型本身验证返回的ModelValidationResult对象的MemberName属性为空字符串;而对于针对属性验证来说,属性名称直接作为MemberName属性值。ModelClientValidationRule集合只有在验证失败的情况下才会返回。如果目标数据符合所有的验证规则,Validate方法会直接返回Null或者一个空ModelValidationResult集合。值得一提的是,我们在调用ModelValidator的Validate方法确定目标数据是否通过验证时,有时候会将方法返回值和定义在类型ValidationResult中具有如下定义的静态只读字段Success进行比较。实际上,表示验证成功的Success字段值就是Null。
 1: public class ValidationResult
 2: {
 3: //其他成员
 4: public static readonly ValidationResult Success;
 5: }
二、DataAnnotationsModelValidator稍微了解ASP.NET MVC的读者应该知道,我们可以通过数据类型的某个属性上应用相应的验证标注特性(比如RequiredAttribute、RangeAttribute和RegularExpressionAttribute等)的方式来定义相应的验证规则,这是ASP.NET MVC 提供的默认Model验证方式。这种基于数据标注(Data Annotation)特性的验证对应的ModelValidator类型为DataAnnotationsModelValidator,我们会在后续的文章中对其进行单独介绍。三、ClientModelValidatorClientModelValidator是定义在程序集System.Web.Mvc.dll中的内部类型,在客户端用于数据类型的验证。如下面的代码片断所示,在构造函数中除了指定Model元数据和Controller上下文之外,还需要以字符串的形式指定验证类型(数据类型)和错误消息。
 1: internal class ClientModelValidator : ModelValidator
 2: {
 3: public ClientModelValidator(ModelMetadata metadata, ControllerContext controllerContext, string validationType,string errorMessage);
 4: public sealed override IEnumerable<ModelClientValidationRule> GetClientValidationRules();
 5: public sealed override IEnumerable<ModelValidationResult> Validate(object container);
 6: }
由于ClientModelValidator仅限于客户端验证,其Validate方法(服务端验证)总是返回一个空的ModelValidationResult集合,而GetClientValidationRules方法会根据指定的验证类型和错误消息生成相应的客户端验证规则。ClientModelValidator具有两个继承者,分别是数值类型和日期类型进行客户端验证的NumericModelValidator和DateModelValidator。如下面的代码片断所示,这两个ClientModelValidator用于表示验证数据类型的字符串分别是“number”和“date”。而表示错误消息的字符串是从内部维护的资源文件中获取的。这实际上带来了一个问题,我们无法对错误消息进行定制。
 1: internal sealed class NumericModelValidator :ClientModelValidator
 2: {
 3: public NumericModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
 4: : base(metadata, controllerContext, "number", ClientDataTypeModelValidatorProvider.GetFieldMustBeNumericResource(controllerContext))
 5: {
 6: }
 7: }
 8:
 9: internal sealed class DateModelValidator :ClientModelValidator
10: {
11: public DateModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
12:: base(metadata, controllerContext,"date", ClientDataTypeModelValidatorProvider.GetFieldMustBeDateResource(controllerContext))
13: {
14: }
15: }