ASP.NET MVC基于标注特性的Model验证:DataAnnotationsModelValidatorProvider
DataAnnotationsModelValidator最终是通过它对应的ModelValidatorProvider,即DataAnnotationsModelValidatorProvider创建的。通过前面的介绍我们知道它是AssociatedValidatorProvider的子类,后者在用于获取ModelValidator的GetValidators方法中已经根据指定的Model元数据所有特性创建出来,DataAnnotationsModelValidator只需要从中筛选出继承自ValiationAttribute的验证特性并创建对象的DataAnnotationsModelValidator就可以了。[本文已经同步到《How ASP.NET MVC Works?》中]
目录 DataAnnotationsModelValidator 基于ValidationAttribute的ModelValidator的创建 基于IValidatableObject的ModelValidator的创建 默认的ModelValidator创建机制 对ModelValidator创建方式的定制
DataAnnotationsModelValidator
我们现在结合DataAnnotationsModelValidator的相关定义来讨论一下具体的ModelValidator提供机制。如下面的代码片断所示,DataAnnotationsModelValidatorProvider具有两个静态的字段AttributeFactories和DefaultAttributeFactory,后者是一个DataAnnotationsModelValidationFactory委托,前者是以此委托为Value以Type对象为Key的字典。
1: public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider
2: {
3: //其他成员
4: internal static readonly Dictionary<Type, DataAnnotationsModelValidationFactory> AttributeFactories;
5: internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory;
6:
7: internal static DataAnnotationsValidatableObjectAdapterFactory DefaultValidatableFactory;
8: internal static readonly Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory> ValidatableFactories;
9:
10: protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, HttpActionContext actionContext, IEnumerable<Attribute> attributes);
11: }
12:
13: public delegate ModelValidator DataAnnotationsModelValidationFactory(ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute);
14:
15: public delegate ModelValidator DataAnnotationsValidatableObjectAdapterFactory(ModelMetadata metadata, ControllerContext context);
基于ValidationAttribute的ModelValidator的创建
委托DataAnnotationsModelValidationFactory根据ModelMetadata、ControllerContext和ValidationAttribute返回一个ModelValidator对象,而字段AttributeFactories表示的字典对象的Key是具体的验证特性的类型,也就是说它维护一个ValidationAttribute特性类型和对应ModelValidator工厂的匹配关系。在重写的GetValidators方法中,针对指定的每一个ValidationAttribute,它先根据其类型从AttributeFactories中获取一个对应的DataAnnotationsModelValidationFactory委托,如果该委托存在,则用它来创建相应的ModelValidator对象;否则就采用字段DefaultAttributeFactory表示的DataAnnotationsModelValidationFactory委托来进行ModelValidator的创建。
基于IValidatableObject的ModelValidator的创建
除了AttributeFactories和DefaultAttributeFactory,DataAnnotationsModelValidatorProvider还具有DefaultValidatableFactory和ValidatableFactories这两个静态属性,它们用于针对可验证对象(实现了IValidatableObject接口)的ModelValidator的创建。DataAnnotationsModelValidator的类型是另外一个类型为DataAnnotationsValidatableObjectAdapterFactory的委托,该委托根据ModelMetadata和ControllerContext创建相应的ModelValidator。ValidatableFactories是一个以此委托为Value,以Type对象为Key的字典。
当DataAnnotationsModelValidatorProvider完成了针对基于验证特性的ModelValidator的创建之后,如果根据Model元数据解析出来的Model类型实现了IValidatableObject接口,那么先从字典ValidatableFactories中根据此类型获取一个对应的DataAnnotationsValidatableObjectAdapterFactory委托,如果匹配的委托对象存在,则用其进行ModelValidator的创建;否则采用通过字段DefaultValidatableFactory表示的默认工厂来创建相应的ModelValidator对象。
默认的ModelValidator创建机制
在DataAnnotationsModelValidatorProvider类型被加载的时候,上述的四个字段会在静态构造函数调用时被初始化。从如下的代码片断可看出,对于一般的ValidationAttribute,对应的ModelValidator是一个DataAnnotationsModelValidator对象(DefaultAttributeFactory字段);针对RangeAttribute、RegularExpressionAttribute 、RequiredAttribute和StringLengthAttribute这四种验证特性,它们对应的适配ModelValidator会被创建出来。而对于可验证对象来说,默认情况下提供的ModelValidator列表中还包含一个ValidatableObjectAdapter对象。
1: public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider
2: {
3: //其他成员
4: static DataAnnotationsModelValidatorProvider()
5: {
6: //1、DefaultAttributeFactory
7: DefaultAttributeFactory = (metadata, context, attribute) => new DataAnnotationsModelValidator(metadata, context, attribute);
8:
9: //2、AttributeFactories
10: Dictionary<Type, DataAnnotationsModelValidationFactory> dictionary = new Dictionary<Type, DataAnnotationsModelValidationFactory>();
11: dictionary.Add(typeof(RangeAttribute), (metadata, context, attribute) => new RangeAttributeAdapter(metadata, context, (RangeAttribute)attribute));
12: dictionary.Add(typeof(RegularExpressionAttribute), (metadata, context, attribute) => new RegularExpressionAttributeAdapter(metadata, context, (RegularExpressionAttribute)attribute));
13: dictionary.Add(typeof(RequiredAttribute), (metadata, context, attribute) => new RequiredAttributeAdapter(metadata, context, (RequiredAttribute)attribute));
14: dictionary.Add(typeof(StringLengthAttribute), (metadata, context, attribute) => new StringLengthAttributeAdapter(metadata, context,(StringLengthAttribute)attribute));
15: AttributeFactories = dictionary;
16:
17: //3、DefaultValidatableFactory
18: DefaultValidatableFactory = (metadata, context) => new ValidatableObjectAdapter(metadata, context);
19:
20: //4、ValidatableFactories
21: ValidatableFactories = new Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory>();
22: }
23: }
对ModelValidator创建方式的定制
DataAnnotationsModelValidatorProvider四个基于委托的静态字段体现了其采用的ModelValidator提供机制。由于它们都是内部字段,我们不能直接对其进行操作,但是如下所示的一系列静态方法在DataAnnotationsModelValidatorProvider中定义出来,使我们可以按照具体的需要对默认的ModelValidator进行定义。
1: public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider
2: {
3: //其他成员
4: public static void RegisterAdapter(Type attributeType, Type adapterType);
5: public static void RegisterAdapterFactory(Type attributeType, DataAnnotationsModelValidationFactory factory);
6: public static void RegisterDefaultAdapter(Type adapterType);
7: public static void RegisterDefaultAdapterFactory(DataAnnotationsModelValidationFactory factory);
8:
9: public static void RegisterDefaultValidatableObjectAdapter(Type adapterType);
10: public static void RegisterDefaultValidatableObjectAdapterFactory(DataAnnotationsValidatableObjectAdapterFactory factory);
11: public static void RegisterValidatableObjectAdapter(Type modelType, Type adapterType);
12: public static void RegisterValidatableObjectAdapterFactory(Type modelType, DataAnnotationsValidatableObjectAdapterFactory factory);
13: }
对于上面的8个静态方法,除了RegisterDefaultAdapter和RegisterValidatableObjectAdapter之外,其余的都很好理解。RegisterDefaultAdapter用于注册一个默认的针对验证特性的ModelValidator类型,该类型必须具有一个参数类型列表为ModelMetadata、ControllerContext和Attribute的构造函数。如果根据 验证特性的类型找到了匹配的DataAnnotationsModelValidationFactory委托对象,相应的参数会被传入该构造函数并最终创建一个我们注册的ModelValidator对象。
RegisterValidatableObjectAdapter和RegisterDefaultAdapter比较类似,用于注册一个默认的针对可验证对象类型的ModelValidator,有该类型必须具有一个参数类型列表为ModelMetadata和ControllerContex的构造函数。如果根据 验证特性的类型找到了匹配的DataAnnotationsValidatableObjectAdapterFactory委托对象,相应的参数会被传入该构造函数并最终创建一个我们注册的ModelValidator对象。
ASP.NET MVC基于标注特性的Model验证:ValidationAttribute ASP.NET MVC基于标注特性的Model验证:DataAnnotationsModelValidator ASP.NET MVC基于标注特性的Model验证:DataAnnotationsModelValidatorProvider ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上 ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则
- 记一次内存溢出的分析经历——thrift带给我的痛orz
- Email系列(QQ邮箱 + 含附件的邮箱案例 + 项目实战)上
- HDU3440 House Man
- redis学习笔记
- Email系列(QQ邮箱 + 含附件的邮箱案例 + 项目实战)下
- 警告:Android P(禁用非官方API)
- 使用JavaScript访问XML数据
- 详解Android UI线程卡顿收集
- 浅谈差分约束问题
- JVM活学活用——类加载机制
- WebAssembly详解及其使用案例
- 30分钟精通快应用
- BZOJ2440: [中山市选2011]完全平方数(莫比乌斯+容斥原理)
- Dapper扩展之~~~Dapper.Contrib
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- c++之数组
- c++之指针
- c++之函数
- kafka的生产者分区机制原理(二)
- (17)Bash别名与快捷键
- (16)Bash历史命令与补全
- 【python-leetcode325-滑动窗口法】最大子数组之和为k
- 爬取51job出现can only concatenate str (not “NoneType“) to str
- springboot之基于注解整合mybatis
- springboot之基于配置文件整合mybatis
- springboot之整合JPA
- springboot之自定义starter
- 【python-leetcode340-滑动窗口法】至多包含 K 个不同字符的最长子串
- 要不是真的喜欢学技术,谁会来爬小姐姐啊。
- springboot缓存之@CachePut注解