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

对于ASP.NET MVC基于标注特性的Model验证,很多人只知道应用在数据类型及其属性上用于定义验证规则和错误消息的ValidationAttribute。通过《ASP.NET MVC以ModelValidator为核心的Model验证体系: ModelValidator》的介绍,我们知道了最终用于进行Model验证的是一个叫做ModelValidator的组件。ValidationAttribute对应的ModelValidator为DataAnnotationsModelValidator,这篇简短的文章为你介绍ASP.NET MVC是如何针对Validation来创建DataAnnotationsModelValidator,以及后者如何利用前者实施Model验证的。[本文已经同步到《How ASP.NET MVC Works?》中]

一、DataAnnotationsModelValidator

ModelValidator是真正用于进行Model验证的组件,上面介绍的验证特性最终被封装成DataAnnotationsModelValidator对象进而被应用到Model验证系统中。如下面的代码片断所示,被封装的ValidationAttribute通过只读属性Attribute表示,该属性在构造函数中被初始化。

   1: public class DataAnnotationsModelValidator : ModelValidator
   2: {
   3:     public DataAnnotationsModelValidator(ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute);
   4:     public override IEnumerable<ModelClientValidationRule>  GetClientValidationRules();
   5:  
   6:     public override IEnumerable<ModelValidationResult> Validate(object container)
   7:     {
   8:         ValidationContext validationContext = new ValidationContext(container ?? this.Metadata.Model, null, null)
   9:         {
  10:             DisplayName = this.Metadata.GetDisplayName()
  11:         };
  12:         ValidationResult validationResult = this.Attribute.GetValidationResult(this.Metadata.Model, validationContext);
  13:         if (validationResult != ValidationResult.Success)
  14:         {
  15:             ModelValidationResult iteratorVariable2 = new ModelValidationResult
  16:             {
  17:                 Message = validationResult.ErrorMessage
  18:             };
  19:             yield return iteratorVariable2;
  20:         }
  21:         else
  22:         {
  23:             yield break;
  24:         }
  25:     }
  26:     protected ValidationAttribute Attribute { get; }
  27:     protected string ErrorMessage { get; }
  28:     public override bool IsRequired { get; }
  29: }

我们给出了用于实施验证的核心方法Validate的完整定义。在该方法中,基于被验证对象(如果为Null则采用Model元数据的Model属性)创建出表示当前验证上下文的ValidationContext对象,并采用Model元数据的DisplayName属性作为该上下文的显示名称。最后直接调用被封装的ValidationAttribute的GetValidationResult方法对指定对象实施验证,如果返回的ValidationResult对象不为空,则以此创建ModelValidationResult对象并返回。

顺便在说说定义在DataAnnotationsModelValidator中的另外两个受保护只读属性的逻辑。用于返回错误消息的ErrorMessage属性来源对对ValidationAttribute的FormatErrorMessage方法的调用,而指定的参数就是当前Model元数据的DisplayName属性。由于只有RequiredAttribute才用于必需字段的验证,所有只有被封装ValidationAttribute为RequiredAttribute时其IsRequired属性返回True。

二、DataAnnotationsModelValidator<TAttribute>

DataAnnotationsModelValidator<TAttribute>是DataAnnotationsModelValidator的子类,其泛型参数为相应的ValidationAttribute的类型,下面的代码片断反映了其定义:

   1: public class DataAnnotationsModelValidator<TAttribute> : DataAnnotationsModelValidator where TAttribute: ValidationAttribute
   2: {    
   3:     public DataAnnotationsModelValidator(ModelMetadata metadata, ModelBindingExecutionContext context, TAttribute attribute);
   4:     protected TAttribute Attribute { get; }
   5: }

作为DataAnnotationsModelValidator与相应ValidationAttribute之间的适配,ASP.NET MVC为常用的ValidationAttribute(RequiredAttribute、RangeAttribute、RegularExpressionAttribute和StringLengthAttribute)定义相应的适配类型。如下面的代码片断所示,它们都是泛型的DataAnnotationsModelValidator<TAttribute>的子类。当我们将这些ValidationAttribute应用到Model类型时,真正用于Model验证的实际上就是这些作为适配的ModelValidator。

   1: public class RequiredAttributeAdapter : DataAnnotationsModelValidator<RequiredAttribute>
   2: {
   3:     public RequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute);
   4:     public override IEnumerable<ModelClientValidationRule> GetClientValidationRules();
   5: }
   6:  
   7: public class RangeAttributeAdapter : DataAnnotationsModelValidator<RangeAttribute>
   8: {    
   9:     public RangeAttributeAdapter(ModelMetadata metadata, ControllerContext context, RangeAttribute attribute);
  10:     public override IEnumerable<ModelClientValidationRule> GetClientValidationRules();
  11: }
  12:  
  13: public class RegularExpressionAttributeAdapter : DataAnnotationsModelValidator<RegularExpressionAttribute>
  14: {    
  15:     public RegularExpressionAttributeAdapter(ModelMetadata metadata, ControllerContext context, RegularExpressionAttribute attribute);
  16:     public override IEnumerable<ModelClientValidationRule> GetClientValidationRules();
  17: }
  18:  
  19: public class StringLengthAttributeAdapter : DataAnnotationsModelValidator<StringLengthAttribute>
  20: {    
  21:     public StringLengthAttributeAdapter(ModelMetadata metadata, ControllerContext context, StringLengthAttribute attribute);
  22:     public override IEnumerable<ModelClientValidationRule>GetClientValidationRules();
  23: }

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,多种验证规则

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏fixzd

redis系列:通过文章点赞排名案例学习sortedset命令

这一篇文章将讲述Redis中的sortedset类型命令,同样也是通过demo来讲述,其他部分这里就不在赘述了。

12740
来自专栏程序员的SOD蜜

C#调用C和C++函数的一点区别

最近做U800电话的二次开发,需要调用厂商的C函数库来打电话,后来想加入通话录音功能,但发现程序默认生产的WAV文件过大,又找了个WAV转MP3的C++函数库程...

26860
来自专栏张善友的专栏

使用 Roslyn 编译器服务

.NET Core和 .NET 4.6中 的C# 6/7 中的编译器Roslyn 一个重要的特性就是"Compiler as a Service",简单的讲,就...

21180
来自专栏生信宝典

R语言学习 - 线图一步法

线图 - 一步绘制 绘图时通常会碰到两个头疼的问题: 有时需要绘制很多的图,唯一的不同就是输入文件,其它都不需要修改。如果用R脚本,需要反复替换文件名,繁琐又容...

28060
来自专栏用户2442861的专栏

CSS基础(七):z-index详解

z-index 属性设置元素的堆叠顺序。拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面。

9410
来自专栏大内老A

ASP.NET MVC Controller激活系统详解:总体设计

我们将整个ASP.NET MVC框架划分为若干个子系统,那么针对请求上下文激活目标Controller对象的子系统被我们成为Controller激活系统。在正式...

22660
来自专栏debugeeker的专栏

某代码查看器的保护突破

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/detai...

7310
来自专栏技术之路

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则

用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeplex.com/ 文档也写的很详细...

30680
来自专栏生信宝典

ETE构建、绘制进化树

ETE能做什么 A Python framework for construction, analysis and visualization of trees...

83050
来自专栏跟着阿笨一起玩NET

对比MS Test与NUnit Test框架

项目中进行Unit Test时,肯定会用到框架,因为这样能够更快捷、方便的进行测试。

9520

扫码关注云+社区

领取腾讯云代金券