ASP.NET MVC下的四种验证编程方式[续篇]

在《ASP.NET MVC下的四种验证编程方式》一文中我们介绍了ASP.NET MVC支持的四种服务端验证的编程方式(“手工验证”、“标注ValidationAttribute特性”、“让数据类型实现IValidatableObject或者IDataErrorInfo”),那么在ASP.NET MVC框架内部是如何提供针对这四种不同编程方式的支持的呢?接下来我们就来聊聊这背后的故事。

一、ModelValidator与ModelValidatorProvider

虽然Model绑定的方式因被验证数据类型的差异而有所不同,但是ASP.NET MVC总是使用一个名为ModelValidator的对象来对绑定的数据对象实施验证。所有的ModelValidator类型均继承自具有如下定义的抽象类ModelValidator。它的GetClientValidationRules方法返回一个元素类型为ModelClientValidationRule的集合,而ModelClientValidationRule是对客户端验证规则的封装,我们会在客户端验证部分对其进行详细介绍。

   1: public abstract class ModelValidator
   2: {
   3:     //其他成员
   4:     virtual IEnumerable<ModelClientValidationRule> GetClientValidationRules();
   5:     abstract IEnumerable<ModelValidationResult> Validate(object container);
   6:  
   7:     virtual bool Isrequired { get; }
   8: }

针对目标数据的验证是通过调用Validate方法来完成的,该方法的输入参数container表示的正是被验证的对象。正是因为被验证的总是一个复杂类型的对象,后者又被称为一个具有若干数据成员的“容器”对象,所以对应的参数被命名为container。Validate方法表示验证结果的返回值并不是一个简单的布尔值,而是一个元素类型为具有如下定义的ModelValidationResult对象集合。

   2: {  
string Message { get; set; }
class ValidationResult
   5: }

ModelValidator具有一个布尔类型的只读属性Isrequired表示该ModelValidator是否对目标数据进行“必需性”验证(即被验证的数据成员必须具有一个具体的值),该属性认返回False。我们可以通过应用requiredAttribute特性将某个属性定义成“必需”的数据成员。

我们知道ASP.NET MVC大都采用Provider的模式来提供相应的组件,比如描述Model元数据的ModelMetadata通过对应的ModelMetadataProvider来提供,实现Model绑定的ModelBinder则可以通过对应的ModelBinderProvider来提供,用于实现Model验证的ModelValidator也不例外,它对应的提供者为ModelValidatorProvider,对应的类型继承自具有如下定义的抽象类ModelValidator Provider。

abstract IEnumerable<ModelValidator> GetValidators(ModelMetadata Metadata,ControllerContext context);
class ModelValidatorProviders
static ModelValidatorProviderCollection Providers { get; }
   5:  
   7: {   
   9:     public ModelValidatorProviderCollection(IList<ModelValidatorProvider> list);
  10:     public IEnumerable<ModelValidator> GetValidators(ModelMetadata Metadata,ControllerContext context);   
  11: }

值得一提的是用于描述Model元数据的ModelMetadata类型具有如下一个GetValidators方法,它返回的ModelValidator列表正是利用注册到ModelValidatorProviders静态属性Providers上的ModelValidatorProvider创建的。

virtual IEnumerable<ModelValidator> GetValidators(ControllerContext context);
class DataAnnotationsModelValidator : ModelValidator
override IEnumerable<ModelClientValidationRule> GetClientValidationRules();
protected internal ValidationAttribute     Attribute { get; }
override bool                       Isrequired { get; }
class ValidatableObjectAdapter : ModelValidator
sealed class DataErrorInfoClassModelValidator : ModelValidator
   5: }
   8: {
class DataErrorInfoModelValidatorProvider : ModelValidatorProvider