ASP.NETMVC Model验证(四)
前言
本篇主要讲解ModelValidatorProvider和ModelValidator两种类型的自定义实现,前者是Model验证提供程序,而ModelValidator类型则是Model验证执行类型,在下面的示例中会使用Model验证提供程序结合Model验证执行类型来执行Model验证,就是使用上个篇幅中所讲的实现个Model绑定器继承自DefaultModelBinder类型,在自定义Model绑定器中使用ModelValidator类型。
Model验证
Model验证简单运用示例
ModelValidator使用生成过程
自定义实现DefaultModelBinder进行验证
自定义ModelValidatorProvider和ModelValidator
ValidationAttribute特性类使用
自定义ValidationAttribute特性类的示例实现
自定义ModelValidatorProvider和ModelValidator
ModelValidator
深呼吸一下,直接进入主题。
在我们定义自定义的ModelValidator类型之前,先看一下ModelValidator类型的定义,代码1-1.
代码1-1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<code> </code><code>public</code> <code>abstract</code> <code>class</code> <code>ModelValidator</code>
<code> </code><code>{</code>
<code> </code><code>protectedModelValidator(ModelMetadata metadata, ControllerContext controllerContext);</code>
<code> </code><code>protectedinternal ControllerContextControllerContext { </code><code>get</code><code>; }</code>
<code> </code><code>public</code> <code>virtual</code> <code>boolIsRequired { </code><code>get</code><code>; }</code>
<code> </code><code>//</code>
<code> </code><code>// 摘要:</code>
<code> </code><code>// 获取模型验证程序的元数据。</code>
<code> </code><code>// 返回结果:</code>
<code> </code><code>// 模型验证程序的元数据。</code>
<code> </code><code>protected</code> <code>internal</code> <code>ModelMetadata Metadata { </code><code>get</code><code>;}</code>
<code> </code><code>public</code> <code>virtual</code> <code>IEnumerable<ModelClientValidationRule>GetClientValidationRules();</code>
<code> </code><code>public</code> <code>static</code> <code>ModelValidatorGetModelValidator(ModelMetadata metadata, ControllerContext context);</code>
<code> </code><code>// 在派生类中实现时验证对象。</code>
<code> </code><code>// 参数:</code>
<code> </code><code>// container:</code>
<code> </code><code>// 容器。</code>
<code> </code><code>// 验证结果的列表。</code>
<code> </code><code>public</code> <code>abstract</code> <code>IEnumerable<ModelValidationResult> Validate(</code><code>object</code> <code>container);</code>
<code> </code><code>}</code>
代码1-1中,我们可以看到ModelValidator类型的构造是可以重写的,这样便于我们自定义一些所需的数据,不过下面的示例中并没有这么做,目的是在于简单的演示,然后我们再看一下Metadata属性,这个属性非常重要了,它表示封装着所要进行验证的Model或者是Model属性的信息在此提醒大家关注一下,最后要看的就是Validate()抽象方法了,我们自定义类型必须实现的这么一个方法,在它的返回类型中有个ModelValidationResult类型,我们就来看一下ModelValidationResult类型,代码1-2.
代码1-2
<code> </code><code>public</code> <code>class</code> <code>ModelValidationResult</code>
<code> </code><code>publicModelValidationResult();</code>
<code> </code>
<code> </code><code>// 获取或设置成员名。</code>
<code> </code><code>// 成员名。</code>
<code> </code><code>public</code> <code>string</code> <code>MemberName { </code><code>get</code><code>;</code><code>set</code><code>; }</code>
<code> </code><code>// 获取或设置验证结果消息。</code>
<code> </code><code>// 验证结果消息。</code>
<code> </code><code>public</code> <code>string</code> <code>Message { </code><code>get</code><code>;</code><code>set</code><code>; }</code>
正如大家所看到的,代码1-2没啥好说的,看完本篇自然明白。
ASP.NET MVC Model验证(三)和ASP.NET MVCModel验证(一)中的示例想必有的朋友是看过了,没看过的朋友建议去快速的看一下篇幅一和篇幅三的示例部分(本篇示例的基础依赖上篇的基础部分,篇幅长度原因这里就不再次说明了),在这里我想说的是Model验证也是分级别的,就是上篇中也有提到过的Model级验证和Model属性级验证,在下面的示例中,我把上篇篇幅中的验证过程拆成三个部分(可以写在一起,便于理解)。
我把第一个部分定义为Model属性级验证,我们来看一下示例代码1-3。
代码1-3
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<code> </code><code>public</code> <code>class</code> <code>MyCustomModelPropertyValidator : ModelValidator</code>
<code> </code><code>publicMyCustomModelPropertyValidator(ModelMetadatamodelMetadata, ControllerContextcontrollContext)</code>
<code> </code><code>: </code><code>base</code><code>(modelMetadata,controllContext)</code>
<code> </code><code>{ }</code>
<code> </code><code>public</code> <code>override</code> <code>IEnumerable<ModelValidationResult> Validate(</code><code>object</code> <code>container)</code>
<code> </code><code>{</code>
<code> </code><code>switch</code><code>(Metadata.PropertyName)</code>
<code> </code><code>{</code>
<code> </code><code>case</code><code>"ID"</code><code>:</code>
<code> </code><code>if</code><code>(</code><code>string</code><code>.IsNullOrEmpty((</code><code>string</code><code>)container)|| (</code><code>string</code><code>)container == </code><code>""</code><code>)</code>
<code> </code><code>{</code>
<code> </code><code>return</code> <code>new</code> <code>ModelValidationResult[]</code>
<code> </code><code>{ </code>
<code> </code><code>new</code> <code>ModelValidationResult()</code>
<code> </code><code>{</code>
<code> </code><code>MemberName=</code><code>"ID"</code><code>,</code>
<code> </code><code>Message= </code><code>"请输入ID,ID不能为空!"</code>
<code> </code><code>}</code>
<code> </code><code>};</code>
<code> </code><code>}</code>
<code> </code><code>break</code><code>;</code>
<code> </code><code>case</code><code>"UserID"</code><code>:</code>
<code> </code><code>MemberName=</code><code>"UserID"</code><code>,</code>
<code> </code><code>Message= </code><code>"请输入用户账户,用户账户不能为空!"</code>
<code> </code><code>case</code><code>"Password1"</code><code>:</code>
<code> </code><code>ControllerContext.Controller.TempData.Add(</code><code>"Password1"</code><code>,</code><code>false</code><code>);</code>
<code> </code><code>MemberName=</code><code>"Password1"</code><code>,</code>
<code> </code><code>Message= </code><code>"请输入登录密码,登录密码不能为空!"</code>
<code> </code><code>case</code><code>"Password2"</code><code>:</code>
<code> </code><code>ControllerContext.Controller.TempData.Add(</code><code>"Password2"</code><code>,</code><code>false</code><code>);</code>
<code> </code><code>MemberName=</code><code>"Pssword2"</code><code>,</code>
<code> </code><code>Message= </code><code>"请再次输入密码,密码不能为空!"</code>
<code> </code><code>case</code><code>"Name"</code><code>:</code>
<code> </code><code>returnEnumerable.Empty<ModelValidationResult>();</code>
<code> </code><code>}</code>
<code> </code><code>returnEnumerable.Empty<ModelValidationResult>();</code>
<code> </code><code>}</code>
首先我们在代码1-3中定义了个MyCustomModelPropertyValidator类型,并且定义了构造函数这点非常重要(看到Model验证提供程序部分就明白了),在Validate()方法中对一些属性进行了基本的的验证,并且依据方法所约束的返回类型去返回,对于代码的实现部分,看过上篇的朋友就知道了在默认的Model绑定器执行Model属性绑定的时候会进行Model属性验证,会在遍历中循环的调用这个MyCustomModelPropertyValidator类型的验证方法,这里有不明白的朋友可以去看一下上篇。
我们再来看第二部分,第二部分的主要验证是验证两次输入的密码是否是相同的,来看示例代码1-4。
代码1-4
<code> </code><code>public</code> <code>class</code> <code>MyCustomModelPassWordValidator : ModelValidator</code>
<code> </code><code>publicMyCustomModelPassWordValidator(ModelMetadatamodelMetadata, ControllerContextcontrollerContext)</code>
<code> </code><code>: </code><code>base</code><code>(modelMetadata,controllerContext)</code>
<code> </code><code>Models.RegistrationInformationregInfo = Metadata.Model </code><code>as</code> <code>Models.RegistrationInformation;</code>
<code> </code><code>if</code><code>(regInfo != </code><code>null</code><code>)</code>
<code> </code><code>if</code><code>(!ControllerContext.Controller.TempData.ContainsKey(</code><code>"Password1"</code><code>)</code>
<code> </code><code>&&!ControllerContext.Controller.TempData.ContainsKey(</code><code>"Password2"</code><code>))</code>
<code> </code><code>{</code>
<code> </code><code>if</code><code>(regInfo.Password1 != regInfo.Password2)</code>
<code> </code><code>{</code>
<code> </code><code>new</code> <code>ModelValidationResult()</code>
<code> </code><code>{</code>
<code> </code><code>MemberName=</code><code>"Password2"</code><code>,</code>
<code> </code><code>Message=</code><code>"请重新输入密码,与上次输入密码不同!"</code>
<code> </code><code>}</code>
<code> </code><code>};</code>
<code> </code><code>}</code>
在代码1-4中,有细心的朋友发现了跟代码1-3的实现方式有很大的区别,对的因为我把这个MyCustomModelPassWordValidator类型定义为Model级验证了,MyCustomModelPassWordValidator类型所被调用的位置是在默认Model绑定器对Model属性验证完毕并且进行绑定了过后,再在默认Model绑定器的OnModelUpdated()方法中调用的,所以上述可以直接通过Metadata的Model属性直接获取Model的值,由此来进行验证,而这句ControllerContext.Controller.TempData.ContainsKey("Password1")代码的含义是判断在Model的Password1属性在属性级验证的时候是否通过了,因为每个Model验证器之间无法传递消息,只有ControllerContext是指向一个引用的,所有用它来做数据信息的承载。在代码1-3中已经定义了。(对于第二部分的理解不太明白的朋友可以结合上篇和本篇来看)
现在我们再看第三部分,意思和第二部分一样,示例代码1-5。
代码1-5
<code> </code><code>public</code> <code>class</code> <code>MyCustomModelNameValidator : ModelValidator</code>
<code> </code><code>publicMyCustomModelNameValidator(ModelMetadatamodelMetadata, ControllerContextcontrollerConttext)</code>
<code> </code><code>: </code><code>base</code><code>(modelMetadata,controllerConttext)</code>
<code> </code><code>if</code><code>(</code><code>string</code><code>.Compare(regInfo.Name, </code><code>"jinyuan"</code><code>, </code><code>true</code><code>)== 0)</code>
<code> </code><code>returnnew ModelValidationResult[]</code>
<code> </code><code>new</code> <code>ModelValidationResult()</code>
<code> </code><code>MemberName=</code><code>""</code><code>,</code>
<code> </code><code>Message=</code><code>"您输入的名称违法了,立即更改不然查水表"</code>
<code> </code><code>}</code>
<code> </code><code>};</code>
代码1-5的功能就是在Model级验证时对Model的Name属性进行验证。
ModelValidatorProvider
上个小节定义了三个部分,第一部分为Model属性级验证,二三部分皆为Model级验证,然而在默认的Model绑定器(DefaultModelBinder类型)执行的时候,它才不管呢,它只负责从ModelValidatorProviders.Providers中获取我们自定义的Model验证器提供程序(ModelValidatorProvider类型实例),再由Model验证器提供程序给它提供Model验证器,这个时候就需要我们的自定义的Model验证器提供程序具有判断我们自身是在哪里被调用的,并且返回对应的Model验证器,来看示例代码1-6。
代码1-6
<code>namespace</code> <code>MvcApplication.ModelValidators</code>
<code>{</code>
<code> </code><code>public</code> <code>class</code> <code>MyCustomModelValidatorProvider:ModelValidatorProvider</code>
<code> </code><code>public</code> <code>override</code> <code>IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContextcontext)</code>
<code> </code><code>if</code><code>(metadata.ContainerType == </code><code>typeof</code><code>(Models.RegistrationInformation))</code>
<code> </code><code>returnnew ModelValidator[]</code>
<code> </code><code>newMyCustomModelPropertyValidator(metadata,context)</code>
<code> </code><code>};</code>
<code> </code><code>elseif (metadata.ModelType == </code><code>typeof</code><code>(Models.RegistrationInformation))</code>
<code> </code><code>new</code> <code>MyCustomModelPassWordValidator(metadata,context),</code>
<code> </code><code>newMyCustomModelNameValidator(metadata,context)</code>
<code> </code><code>returnEnumerable.Empty<ModelValidator>();</code>
<code>}</code>
在代码1-6中,我们定义了个自定义的Model验证器提供程序MyCustomModelValidatorProvider类型,在MyCustomModelValidatorProvider类型中是根据GetValidators()方法的参数metadata所包含的信息来判断自己被默认的Model绑定器(DefaultModelBinder类型)调用的位置。(对于Model元数据部分大家可查看我前面跟大家分享的Model元数据系列)
到了这里几乎就已经全部完成了,现在注册到系统中是不能使用的,有的朋友会骂了,不能用瞎扯蛋扯半天,大家莫急,听我解释,是因为我们自定义的Model验证器和Model验证器提供程序都要受到MVC框架的默认的Model绑定器(DefaultModelBinder类型)调用的约束,是必须按照它方法内部定义的来往下写,在这里我们不图省事,再定义一个自定义实现DefaultModelBinder类型的Model绑定器,来看示例代码1-7。
代码1-7
<code> </code><code>public</code> <code>class</code> <code>MyCustomModelValidatorDefaultModelBinder : DefaultModelBinder</code>
<code> </code><code>protectedoverride voidSetProperty(ControllerContextcontrollerContext, ModelBindingContextbindingContext, PropertyDescriptorpropertyDescriptor, </code><code>object</code> <code>value)</code>
<code> </code><code>base</code><code>.SetProperty(controllerContext,bindingContext, propertyDescriptor, value);</code>
<code> </code><code>foreach</code><code>(ModelValidator modelValidator </code><code>in</code> <code>ModelValidatorProviders.Providers.GetValidators(bindingContext.PropertyMetadata[propertyDescriptor.Name],controllerContext))</code>
<code> </code><code>IEnumerable<ModelValidationResult> modelValidationResults =modelValidator.Validate(value);</code>
<code> </code><code>foreach</code><code>(ModelValidationResult modelValidationResultin modelValidationResults)</code>
<code> </code><code>bindingContext.ModelState.AddModelError(modelValidationResult.MemberName,modelValidationResult.Message);</code>
<code> </code><code>protectedoverride voidOnModelUpdated(ControllerContextcontrollerContext, ModelBindingContextbindingContext)</code>
<code> </code><code>//base.OnModelUpdated(controllerContext,bindingContext);</code>
<code> </code><code>foreach</code><code>(ModelValidator modelValidator </code><code>in</code> <code>ModelValidatorProviders.Providers.GetValidators(bindingContext.ModelMetadata,controllerContext))</code>
<code> </code><code>IEnumerable<ModelValidationResult> modelValidationResults =modelValidator.Validate(</code><code>null</code><code>);</code>
<code> </code><code>bindingContext.ModelState.AddModelError(modelValidationResult.MemberName,modelValidationResult.Message);</code>
有了代码1-7中的Model绑定器就可以吻合我们前面所定义的Model验证器以及提供程序了。
我要把MyCustomModelValidatorProvider类型和MyCustomModelValidatorDefaultModelBinder类型注册到系统中,将示例代码1-8部分添加至Global.asax文件的Application_Start()方法中。
代码1-8
<code>ModelBinders.Binders.Add(</code><code>typeof</code><code>(Models.RegistrationInformation), newBinders.MyCustomModelValidatorDefaultModelBinder());</code>
<code>ModelValidatorProviders.Providers.Insert(0, newModelValidators.MyCustomModelValidatorProvider());</code>
看下图1,图1为初始的展示页面,图2为图1中点击提交后执行验证过后。
图1
<a href="http://s3.51cto.com/wyfs02/M02/3D/23/wKiom1PD0VXzie6XAAEJrDFD7Mw021.jpg" target="_blank"></a>
图2
<a href="http://s3.51cto.com/wyfs02/M00/3D/23/wKioL1PD0TfzgIHTAAHA1OkfjUQ569.jpg" target="_blank"></a>
本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1438118,如需转载请自行联系原作者