旨在为目标Action方法的执行绑定输入参数的Model绑定过程伴随着对Model的验证。借助相应的验证特性,我们可以直接以声明的方式在Model类型上定义验证规则,这些规则将会作为Model元数据的一部分。具体在Model绑定过程中,ModelBinder通过ValueProvider为Model对象的某个属性提供相应属性值之后,会根据定义在基于该属性的Model元数据的验证规则实施验证。ASP.NET MVC的整个Model验证系统以组件ModelValidator为核心,或者说Model对象的验证最终通过某个ModelValidator对象来完成,所以我们有必要先来认识一下ModelValidator以及背后的提供机制。[本文已经同步到《How ASP.NET MVC Works?》中]

目录
一、ModelValidator
二、DataAnnotationsModelValidator
三、ClientModelValidator
四、DataErrorInfoModelValidator
五、ValidatableObjectAdapter

一、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,我们会在后续的文章中对其进行单独介绍。

三、ClientModelValidator

ClientModelValidator是定义在程序集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, "", 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,  "", ClientDataTypeModelValidatorProvider.GetFieldMustBeDateResource(controllerContext))
  13:     {
  14:     }
  15: }

四、DataErrorInfoModelValidator

在System.ComponentModel命名空间下定义了一个名为IDataErrorInfo的接口,该接口提供了一种标准的错误信息定制方式。如下面的代码片断所示,IDataErrorInfo具有两个成员,只读属性Error用于获取基于自身的错误消息,而只读索引用于返回指定数据成员的错误消息。

   1: public interface IDataErrorInfo
   2: {
   3:     string Error { get; }
   4:     string this[string columnName] { get; }
   5: }

ASP.NET MVC的Model验证系统为实现了IDataErrorInfo接口的数据对象的验证定义专门的ModelValidator。具体来说,对于一个类型实现了IDataErrorInfo接口的数据对象,我们可以通过DataErrorInfoClassModelValidator对该对象本身实施验证,DataErrorInfoClassModelValidator会将Error属性表示的错误消息转换为表示验证结果的ModelValidationResult对象。而对于该对象的属性的验证则采用另一个类型为DataErrorInfoPropertyModelValidator对象,DataErrorInfoPropertyModelValidator会将属性名称作为调用索引的参数从而获得相应的错误消息,并进一步转换成ModelValidationResult对象返回。DataErrorInfoPropertyModelValidator和DataErrorInfoPropertyModelValidator都是定义在程序集System.Web.Mvc.dll中的内部类型,并不对外公布。

五、ValidatableObjectAdapter

在System.ComponentModel.DataAnnotations命名空间下定义了一个IValidatableObject接口,它代表另外一种验证的模式,我个人将其称为“自我验证”,即数据对象自行实现针对自身的验证。如下面的代码片断所示,针对自身的验证实现在IValidatableObject的Validate方法中。

   1: public interface IValidatableObject
   2: {
   3:     IEnumerable<ValidationResult> Validate(ValidationContext validationContext);
   4: }

ASP.NET Model验证系统定义了专门的ModelValidator来验证种实现了IValidatableObject接口的数据对象,其类型为ValidatableObjectAdapter。由于被验证本身已经将验证实现在了Validate方法中,所以ValidatableObjectAdapter只需要调用该方法并将验证结果从ValidationResult类型转换成ModelValidationResult类型即可。

   1: public class ValidatableObjectAdapter : ModelValidator
   2: {
   3:     public ValidatableObjectAdapter(ModelMetadata metadata, ControllerContext context);
   4:     public override IEnumerable<ModelValidationResult> Validate(object container);
   5: }

ASP.NET MVC以ModelValidator为核心的Model验证体系: ModelValidator
ASP.NET MVC以ModelValidator为核心的Model验证体系: ModelValidatorProvider
ASP.NET MVC以ModelValidator为核心的Model验证体系: ModelValidatorProviders

转载于:https://www.cnblogs.com/artech/archive/2012/06/01/model-validator-01.html

ASP.NET MVC以ModelValidator为核心的Model验证体系: ModelValidator相关推荐

  1. ASP.NET MVC以ValueProvider为核心的值提供系统: DictionaryValueProvider

    NameValueCollectionValueProvider采用一个NameValueCollection作为数据源,DictionnaryValueProvider的数据源类型自然就是一个Dic ...

  2. 在Asp.Net MVC中实现RequiredIf标签对Model中的属性进行验证

    在Asp.Net MVC中可以用继承ValidationAttribute的方式,自定制实现RequiredIf标签对Model中的属性进行验证 具体场景为:某一属性是否允许为null的验证,要根据另 ...

  3. ASP.NET MVC 3.0学习系列文章—Model in ASP.NET MVC 3.0

    系列文章 ASP.NET MVC 3.0学习系列文章-序 ASP.NET MVC 3.0学习系列文章--Razor and ASP.NET MVC 3.0 ASP.NET MVC 3.0学习系列文章- ...

  4. ASP.NET MVC 入门8、ModelState与数据验证

    ViewData有一个ModelState的属性,这是一个类型为ModelStateDictionary的ModelState类型的字典集合.在进行数据验证的时候这个属性是比较有用的.在使用Html. ...

  5. ASP.NET MVC基于标注特性的Model验证:DataAnnotationsModelValidator

    对于ASP.NET MVC基于标注特性的Model验证,很多人只知道应用在数据类型及其属性上用于定义验证规则和错误消息的ValidationAttribute.通过<ASP.NET MVC以Mo ...

  6. How ASP.NET MVC Works?

    一.ASP.NET + MVC IIS与ASP.NET管道 MVC.MVP以及Model2[上篇] MVC.MVP以及Model2[下篇] ASP.NET MVC是如何运行的[1]: 建立在" ...

  7. ASP.NET MVC 4框架揭秘

    ASP.NET MVC 4框架揭秘(国内第一部Asp.net MVC 4图书,.NET名家名作,深度剖析) 蒋金楠 著 ISBN 978-7-121-19049-0 2013年1月出版 定价:89.0 ...

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

    ASP.NET MVC下的四种验证编程方式[续篇] 原文:ASP.NET MVC下的四种验证编程方式[续篇] 在<ASP.NET MVC下的四种验证编程方式>一文中我们介绍了ASP.NET ...

  9. 13个 ASP.NET MVC 的扩展

    ASP.NET MVC设计的主要原则之一是可扩展性.处理管线(processing pipeline)上的所有(或大多数)东西都是可替换的.因此,如果您不喜欢ASP.NET MVC所使用的约定(或缺乏 ...

最新文章

  1. 初识HTML流水笔记
  2. 后端技术:MyBatis 批量插入的 3 种写法
  3. 欧拉函数 cojs 2181. 打表
  4. 修改MyEclipse/Eclipse左侧文字大小(MacOS/Windows)
  5. 设有n个正整数,将他们连接成一排,组成一个最大的多位整数
  6. 怎么更改Windows11鼠标指针大小和样式
  7. Typora本地图片上传
  8. Django项目部署(nginx1.18+uwgsi)
  9. python数据类型—字符串
  10. java中的异常处理代码,java_深入剖析Java中的各种异常处理方式,1. 调试追踪代码:public s - phpStudy...
  11. 欧美民用航空器 DO-178B标准
  12. 提高专业技能之 “专利申请”
  13. api. feel.ai_如何使用Api.ai构建自己的AI助手
  14. 重量级ORM框架--持久化框架Hibernate【关系映射详解】
  15. Android超强大的粒子动画库,流星雨,爆炸,满屏飞花,等粒子特效快速实现
  16. 有机化学研究生博士生为什么被要求长时间工作
  17. 为什么不要去小公司上班?这是我血与泪的教训!!!
  18. Android中高级进阶开发面试题冲刺合集(四)
  19. Vlan间通信原理(HCIA)
  20. python菜鸟学习Day9(requests,套接字socket)

热门文章

  1. 网站被K的解决方案有哪些?
  2. 网站排名优化看技巧!
  3. 图的深度搜索c语言,求图的深度优先搜索!该怎么处理
  4. 轨迹分析_单细胞轨迹分析知多少拟时间分析比较
  5. Java IO在Android中应用(三):Apk加固去壳
  6. 开发日记-20190813 关键词 读书笔记《Linux 系统管理技术手册(第二版)》DAY 22
  7. Intel daal4py demo运行过程
  8. parquet文件格式——本质上是将多个rows作为一个chunk,同一个chunk里每一个单独的column使用列存储格式,这样获取某一row数据时候不需要跨机器获取...
  9. 一些开源搜索引擎实现——倒排使用原始文件,列存储Hbase,KV store如levelDB、mongoDB、redis,以及SQL的,如sqlite或者xxSQL...
  10. 学习webpack记录(三)