这里有新鲜出炉的精品教程,程序狗速度看过来!
ASP.NET 是. NET FrameWork 的一部分,是一项微软公司的技术,是一种使嵌入网页中的脚本可由因特网服务器执行的服务器端脚本技术,它可以在通过 HTTP 请求文档时再在 web 服务器上动态创建它们。 指 Active Server Pages(动态服务器页面) ,运行于 IIS(Internet Information Server 服务,是 Windows 开发的 Web 服务器)之中的程序 。
ASP.NET MVC 支持四种服务端验证的编程方式("手工验证"、"标注 ValidationAttribute 特性"、"让数据类型实现 IValidatableObject 或者 IDataErrorInfo"),那么在 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 是对客户端验证规则的封装,我们会在客户端验证部分对其进行详细介绍。
- public abstract class ModelValidator
- {
- //其他成员
- public virtual IEnumerable<ModelClientValidationRule> GetClientValidationRules();
- public abstract IEnumerable<ModelValidationResult> Validate(object container);
- public virtual bool IsRequired { get; }
- }
针对目标数据的验证是通过调用 Validate 方法来完成的,该方法的输入参数 container 表示的正是被验证的对象。正是因为被验证的总是一个复杂类型的对象,后者又被称为一个具有若干数据成员的 "容器" 对象,所以对应的参数被命名为 container。Validate 方法表示验证结果的返回值并不是一个简单的布尔值,而是一个元素类型为具有如下定义的 ModelValidationResult 对象集合。
- public class ModelValidationResult
- {
- public string MemberName { get; set; }
- public string Message { get; set; }
- }
ModelValidationResult 具有两个字符串类型属性 MemberName 和 Message,前者代表被验证数据成员的名称,后者表示错误消息。一般来说,如果 ModelValidationResult 对象来源于针对容器对象本身的验证,它的 MemberName 属性为空字符串。对于针对容器对象某个属性的验证来说,属性名称会作为返回的 ModelValidationResult 对象的 MemberName 属性。
ModelValidationResult 集合只有在验证失败的情况下才会返回。如果被验证数据对象符合所有的验证规则,Validate 方法会直接返回 Null 或者一个空 ModelValidationResult 集合。值得一提的是,我们有时候会用 ValidationResult 的静态只读字段 Success 表示成功通过验证的结果,实际上该字段的值就是 Null。
- public class ValidationResult
- {
- //其他成员
- public static readonly ValidationResult Success;
- }
ModelValidator 具有一个布尔类型的只读属性 IsRequired 表示该 ModelValidator 是否对目标数据进行 "必需性" 验证(即被验证的数据成员必须具有一个具体的值),该属性默认返回 False。我们可以通过应用 RequiredAttribute 特性将某个属性定义成 "必需" 的数据成员。
我们知道 ASP.NET MVC 大都采用 Provider 的模式来提供相应的组件,比如描述 Model 元数据的 ModelMetadata 通过对应的 ModelMetadataProvider 来提供,实现 Model 绑定的 ModelBinder 则可以通过对应的 ModelBinderProvider 来提供,用于实现 Model 验证的 ModelValidator 也不例外,它对应的提供者为 ModelValidatorProvider,对应的类型继承自具有如下定义的抽象类 ModelValidator Provider。
- public abstract class ModelValidatorProvider
- {
- public abstract IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context);
- }
如上面的代码片段所示,GetValidators 方法具有两个参数,一个是用于描述被验证类型或者属性 Model 元数据的 ModelMetadata 对象,另一个是当前 ControllerContext。该方法返回的是一个元素类型为 ModelValidator 的集合。
ASP.NET MVC 通过静态类型 ModelValidatorProviders 对使用的 ModelValidatorProvider 进行注册。如下面的代码片段所示,ModelValidatorProviders 具有一个静态只读属性 Providers,对应的类型为 ModelValidatorProviderCollection,它表示基于整个 Web 应用范围的全局 ModelValidatorProvider 集合。
- public static class ModelValidatorProviders {
- public static ModelValidatorProviderCollection Providers {
- get;
- }
- }
- public class ModelValidatorProviderCollection: Collection < ModelValidatorProvider > {
- public ModelValidatorProviderCollection();
- public ModelValidatorProviderCollection(IList < ModelValidatorProvider > list);
- public IEnumerable < ModelValidator > GetValidators(ModelMetadata metadata, ControllerContext context);
- }
值得一提的是用于描述 Model 元数据的 ModelMetadata 类型具有如下一个 GetValidators 方法,它返回的 ModelValidator 列表正是利用注册到 ModelValidatorProviders 静态属性 Providers 上的 ModelValidatorProvider 创建的。
- public class ModelMetadata
- {
- //其他成员
- public virtual IEnumerable<ModelValidator> GetValidators(ControllerContext context);
- }
如右图所示的 UML 列出了组成 Model 验证系统的三个核心类型。具体的 Model 验证工作总是通过某个具体的 ModelValidator 来完成,作为 ModelValidator 提供者的 ModelValidatorProvider 注册在静态类型 ModelValidatorProviders 之上。
二、DataAnnotationsModelValidator
我们在《ASP.NET MVC 下的四种验证编程方式》中介绍了三种不同的 "自动化验证" 的编程方式,ASP.NET MVC 在内部会采用不同的 ModelValidator 来对绑定的参数实施验证。一个具体的 ModelValidator 通常有相应的 ModelValidatorProvider 来提供,接下来的内容中将对 ASP.NET MVC 提供的原生的 ModelValidator 和对应的 ModelValidatorProvider 作详细的介绍。
对于上面提到的这三种验证编程方式,第一种(利用应用在数据类型或其数据成员上的 ValidationAttribute 特性来定义相应的验证规则)是最为常用的。基于 ValidationAttribute 特性这种声明式验证解决方案最终通过 DataAnnotationsModelValidator 来完成。一个 DataAnnotationsModelValidator 对象实际上是对一个 ValidationAttribute 特性的封装,这可以从如下所示的定义看出来。
- public class DataAnnotationsModelValidator : ModelValidator
- {
- public DataAnnotationsModelValidator(ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute);
- public override IEnumerable<ModelClientValidationRule> GetClientValidationRules();
- public override IEnumerable<ModelValidationResult> Validate(object container);
- protected internal ValidationAttribute Attribute { get; }
- protected internal string ErrorMessage { get; }
- public override bool IsRequired { get; }
- }
DataAnnotationsModelValidator 的提供者为 DataAnnotationsModelValidatorProvider, 关于 ValidationAttribute、DataAnnotationsModelValidator 和 DataAnnotationsModelValidatorProvider 的详细内容可以参考之前写的三篇文章。
ASP.NET MVC 基于标注特性的 Model 验证:ValidationAttribute
ASP.NET MVC 基于标注特性的 Model 验证:DataAnnotationsModelValidator
ASP.NET MVC 基于标注特性的 Model 验证:DataAnnotationsModelValidatorProvider
三、ValidatableObjectAdapter
如果被验证的数据类型实现了 IValidatable 接口,ASP.NET MVC 会自动调用实现的 Validate 方法对其实施验证,此时创建的 ModelValidator 是一个 ValidatableObjectAdapter 对象。ValidatableObjectAdapter 定义如下,其 Validate 方法的实现逻辑很简单:它直接调用被验证对象的 Validate 方法,并将返回的 ValidationResult 对象转换成 ModelValidationResult 类型。
- public class ValidatableObjectAdapter : ModelValidator
- {
- public ValidatableObjectAdapter(ModelMetadata metadata, ControllerContext context);
- public override IEnumerable<ModelValidationResult> Validate(object container);
- }
虽然 ValidatableObjectAdapter 继承自 ModelValidator,但是 ASP.NET MVC 貌似没有将其视为一个真正意义上的 ModelValidator,而是将其视为一个 "适配器(Adapter)"。ASP.NET MVC 也没有为 ValidatableObjectAdapter 定义单独的 ModelValidatorProvider,它的提供者其实是上面提到过的 DataAnnotationsModelValidatorProvider。
四、DataErrorInfoModelValidator
如果我们让数据类型实现 IDataErrorInfo 接口,可以利用实现的 Error 属性和索引提供针对自身以及所属数据成员的验证错误信息。针对这样的数据类型,ASP.NET MVC 最终会创建一个 DataErrorInfoModelValidator 对象来对其实施验证,DataErrorInfoClassModelValidator 和 DataErrorInfoPropertyModelValidator 是两个具体的 DataErrorInfoModelValidator。
DataErrorInfoClassModelValidator 和 DataErrorInfoPropertyModelValidator 是两个内部类型。前者针对容器对象自身实施验证,所以它只需要从实现的 Error 属性中提取错误消息并将其转换成返回的 ModelValidationResult 对象。后者则专门验证容器对象的某个属性,它在实现的 Validate 方法中会利用属性名从实现的索引中提取相应的错误消息并将其转换成返回的 ModelValidationResult 对象。
- internal sealed class DataErrorInfoClassModelValidator : ModelValidator
- {
- public DataErrorInfoClassModelValidator(ModelMetadata metadata, ControllerContext controllerContext);
- public override IEnumerable<ModelValidationResult> Validate(object container);
- }
- internal sealed class DataErrorInfoPropertyModelValidator : ModelValidator
- {
- public DataErrorInfoPropertyModelValidator(ModelMetadata metadata, ControllerContext controllerContext);
- public override IEnumerable<ModelValidationResult> Validate(object container);
- }
ASP.NET MVC 最终利用具有如下定义的 DataErrorInfoModelValidatorProvider 来提供这两种类型的 DataErrorInfoModelValidator。对于其实现的 GetValidators 方法来说,如果被验证对象的类型实现了 IDataErrorInfo 接口,它会创建一个 DataErrorInfoClassModelValidator 对象并添加到返回的 ModelValidator 列表中。如果被验证的是容器类型的某个属性值并且容器类型实现了 IDataErrorInfo 接口,它会创建一个 DataErrorInfoPropertyModelValidator 对象并添加到返回的 ModelValidator 列表中。
- public class DataErrorInfoModelValidatorProvider : ModelValidatorProvider
- {
- public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context);
- }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,同时也希望多多支持 PHPERZ!
来源: http://www.phperz.com/article/17/0815/338132.html