ASP.NETMVC Model验证(四)

简介:

ASP.NETMVC Model验证()

前言

本篇主要讲解ModelValidatorProviderModelValidator两种类型的自定义实现,前者是Model验证提供程序,而ModelValidator类型则是Model验证执行类型,在下面的示例中会使用Model验证提供程序结合Model验证执行类型来执行Model验证,就是使用上个篇幅中所讲的实现个Model绑定器继承自DefaultModelBinder类型,在自定义Model绑定器中使用ModelValidator类型

Model验证

  • Model验证简单运用示例

  • ModelValidator使用生成过程

  • 自定义实现DefaultModelBinder进行验证

  • 自定义ModelValidatorProviderModelValidator 

  • ValidationAttribute特性类使用

  • 自定义ValidationAttribute特性类的示例实现

 

自定义ModelValidatorProviderModelValidator

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
     public  abstract  class  ModelValidator
     {
         protectedModelValidator(ModelMetadata metadata, ControllerContext controllerContext);
         protectedinternal ControllerContextControllerContext {  get ; }
         public  virtual  boolIsRequired {  get ; }
         //
         // 摘要:
         //     获取模型验证程序的元数据。
         //
         // 返回结果:
         //     模型验证程序的元数据。
         protected  internal  ModelMetadata Metadata {  get ;}
         public  virtual  IEnumerable<ModelClientValidationRule>GetClientValidationRules();
         public  static  ModelValidatorGetModelValidator(ModelMetadata metadata, ControllerContext context);
         //
         // 摘要:
         //     在派生类中实现时验证对象。
         //
         // 参数:
         //   container:
         //     容器。
         //
         // 返回结果:
         //     验证结果的列表。
         public  abstract  IEnumerable<ModelValidationResult> Validate( object  container);
     }


代码1-1中,我们可以看到ModelValidator类型的构造是可以重写的,这样便于我们自定义一些所需的数据,不过下面的示例中并没有这么做,目的是在于简单的演示,然后我们再看一下Metadata属性,这个属性非常重要了,它表示封装着所要进行验证的Model或者是Model属性的信息在此提醒大家关注一下,最后要看的就是Validate()抽象方法了,我们自定义类型必须实现的这么一个方法,在它的返回类型中有个ModelValidationResult类型,我们就来看一下ModelValidationResult类型,代码1-2.

代码1-2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
     public  class  ModelValidationResult
     {
         publicModelValidationResult();
  
         // 摘要:
         //     获取或设置成员名。
         //
         // 返回结果:
         //     成员名。
         public  string  MemberName {  get ; set ; }
         //
         // 摘要:
         //     获取或设置验证结果消息。
         //
         // 返回结果:
         //     验证结果消息。
         public  string  Message {  get ; set ; }
     }


正如大家所看到的,代码1-2没啥好说的,看完本篇自然明白。

ASP.NET MVC Model验证()ASP.NET MVCModel验证()中的示例想必有的朋友是看过了,没看过的朋友建议去快速的看一下篇幅一和篇幅三的示例部分(本篇示例的基础依赖上篇的基础部分,篇幅长度原因这里就不再次说明了),在这里我想说的是Model验证也是分级别的,就是上篇中也有提到过的Model级验证和Model属性级验证,在下面的示例中,我把上篇篇幅中的验证过程拆成三个部分(可以写在一起,便于理解)。

我把第一个部分定义为Model属性级验证,我们来看一下示例代码1-3

代码1-3

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
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
     public  class  MyCustomModelPropertyValidator : ModelValidator
     {
         publicMyCustomModelPropertyValidator(ModelMetadatamodelMetadata, ControllerContextcontrollContext)
             base (modelMetadata,controllContext)
         { }
  
         public  override  IEnumerable<ModelValidationResult> Validate( object  container)
         {
             switch (Metadata.PropertyName)
             {
                 case "ID" :
                     if ( string .IsNullOrEmpty(( string )container)|| ( string )container ==  "" )
                     {
                         return  new  ModelValidationResult[]
                            
                                new  ModelValidationResult()
                                {
                                    MemberName= "ID" ,
                                    Message=  "请输入ID,ID不能为空!"
                                }
                             };
                     }
                     break ;
                 case "UserID" :
                     if ( string .IsNullOrEmpty(( string )container)|| ( string )container ==  "" )
                     {
                         return  new  ModelValidationResult[]
                            
                                new  ModelValidationResult()
                                {
                                    MemberName= "UserID" ,
                                    Message=  "请输入用户账户,用户账户不能为空!"
                                }
                             };
                     }
                     break ;
                 case "Password1" :
                     if ( string .IsNullOrEmpty(( string )container)|| ( string )container ==  "" )
                     {
                        ControllerContext.Controller.TempData.Add( "Password1" , false );
                         return  new  ModelValidationResult[]
                            
                                new  ModelValidationResult()
                                {
                                    MemberName= "Password1" ,
                                    Message=  "请输入登录密码,登录密码不能为空!"
                                }
                             };
                     }
                     break ;
                 case "Password2" :
                     if ( string .IsNullOrEmpty(( string )container)|| ( string )container ==  "" )
                     {
                        ControllerContext.Controller.TempData.Add( "Password2" , false );
                         return  new  ModelValidationResult[]
                            
                                new  ModelValidationResult()
                                {
                                    MemberName= "Pssword2" ,
                                    Message=  "请再次输入密码,密码不能为空!"
                                }
                             };
                     }
                     break ;
                 case "Name" :
                     returnEnumerable.Empty<ModelValidationResult>();
  
             }
             returnEnumerable.Empty<ModelValidationResult>();
         }
     }


首先我们在代码1-3中定义了个MyCustomModelPropertyValidator类型,并且定义了构造函数这点非常重要(看到Model验证提供程序部分就明白了),在Validate()方法中对一些属性进行了基本的的验证,并且依据方法所约束的返回类型去返回,对于代码的实现部分,看过上篇的朋友就知道了在默认的Model绑定器执行Model属性绑定的时候会进行Model属性验证,会在遍历中循环的调用这个MyCustomModelPropertyValidator类型的验证方法,这里有不明白的朋友可以去看一下上篇。

我们再来看第二部分,第二部分的主要验证是验证两次输入的密码是否是相同的,来看示例代码1-4

代码1-4

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
27
28
29
30
     public  class  MyCustomModelPassWordValidator : ModelValidator
     {
         publicMyCustomModelPassWordValidator(ModelMetadatamodelMetadata, ControllerContextcontrollerContext)
             base (modelMetadata,controllerContext)
         { }
  
         public  override  IEnumerable<ModelValidationResult> Validate( object  container)
         {
             Models.RegistrationInformationregInfo = Metadata.Model  as  Models.RegistrationInformation;
             if (regInfo !=  null )
             {
                 if (!ControllerContext.Controller.TempData.ContainsKey( "Password1" )
                     &&!ControllerContext.Controller.TempData.ContainsKey( "Password2" ))
                 {
                     if (regInfo.Password1 != regInfo.Password2)
                     {
                         return  new  ModelValidationResult[]
                         {
                             new  ModelValidationResult()
                             {
                                 MemberName= "Password2" ,
                                 Message= "请重新输入密码,与上次输入密码不同!"
                             }
                         };
                     }
                 }
             }
             returnEnumerable.Empty<ModelValidationResult>();
         }
     }


在代码1-4中,有细心的朋友发现了跟代码1-3的实现方式有很大的区别,对的因为我把这个MyCustomModelPassWordValidator类型定义为Model级验证了MyCustomModelPassWordValidator类型所被调用的位置是在默认Model绑定器对Model属性验证完毕并且进行绑定了过后,再在默认Model绑定器的OnModelUpdated()方法中调用的,所以上述可以直接通过MetadataModel属性直接获取Model的值,由此来进行验证,而这句ControllerContext.Controller.TempData.ContainsKey("Password1")代码的含义是判断在ModelPassword1属性在属性级验证的时候是否通过了,因为每个Model验证器之间无法传递消息,只有ControllerContext是指向一个引用的,所有用它来做数据信息的承载。在代码1-3中已经定义了。(对于第二部分的理解不太明白的朋友可以结合上篇和本篇来看)

现在我们再看第三部分,意思和第二部分一样,示例代码1-5

代码1-5

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
     public  class  MyCustomModelNameValidator : ModelValidator
     {
         publicMyCustomModelNameValidator(ModelMetadatamodelMetadata, ControllerContextcontrollerConttext)
             base (modelMetadata,controllerConttext)
         { }
  
         public  override  IEnumerable<ModelValidationResult> Validate( object  container)
         {
             Models.RegistrationInformationregInfo = Metadata.Model  as  Models.RegistrationInformation;
             if (regInfo !=  null )
             {
                 if ( string .Compare(regInfo.Name,  "jinyuan" true )== 0)
                 {
                     returnnew ModelValidationResult[]
                     {
                         new  ModelValidationResult()
                         {
                             MemberName= "" ,
                             Message= "您输入的名称违法了,立即更改不然查水表"
                         }
                     };
                 }
             }
             returnEnumerable.Empty<ModelValidationResult>();
         }
     }


代码1-5的功能就是在Model级验证时对ModelName属性进行验证。

 

ModelValidatorProvider

上个小节定义了三个部分,第一部分为Model属性级验证,二三部分皆为Model级验证,然而在默认的Model绑定器(DefaultModelBinder类型)执行的时候,它才不管呢,它只负责从ModelValidatorProviders.Providers中获取我们自定义的Model验证器提供程序(ModelValidatorProvider类型实例),再由Model验证器提供程序给它提供Model验证器,这个时候就需要我们的自定义的Model验证器提供程序具有判断我们自身是在哪里被调用的,并且返回对应的Model验证器,来看示例代码1-6

代码1-6

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
namespace  MvcApplication.ModelValidators
{
     public  class  MyCustomModelValidatorProvider:ModelValidatorProvider
     {
         public  override  IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContextcontext)
         {
             if (metadata.ContainerType ==  typeof (Models.RegistrationInformation))
             {
                 returnnew ModelValidator[]
                 {
                     newMyCustomModelPropertyValidator(metadata,context)
                 };
             }
             elseif (metadata.ModelType ==  typeof (Models.RegistrationInformation))
             {
                 returnnew ModelValidator[]
                 {
                     new  MyCustomModelPassWordValidator(metadata,context),
                     newMyCustomModelNameValidator(metadata,context)
                 };
             }
             returnEnumerable.Empty<ModelValidator>();
         }
     }
}


在代码1-6中,我们定义了个自定义的Model验证器提供程序MyCustomModelValidatorProvider类型,在MyCustomModelValidatorProvider类型中是根据GetValidators()方法的参数metadata所包含的信息来判断自己被默认的Model绑定器(DefaultModelBinder类型)调用的位置。(对于Model元数据部分大家可查看我前面跟大家分享的Model元数据系列)

到了这里几乎就已经全部完成了,现在注册到系统中是不能使用的,有的朋友会骂了,不能用瞎扯蛋扯半天,大家莫急,听我解释,是因为我们自定义的Model验证器和Model验证器提供程序都要受到MVC框架的默认的Model绑定器(DefaultModelBinder类型)调用的约束,是必须按照它方法内部定义的来往下写,在这里我们不图省事,再定义一个自定义实现DefaultModelBinder类型的Model绑定器,来看示例代码1-7

代码1-7

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
27
28
     public  class  MyCustomModelValidatorDefaultModelBinder : DefaultModelBinder
     {
         protectedoverride voidSetProperty(ControllerContextcontrollerContext, ModelBindingContextbindingContext, PropertyDescriptorpropertyDescriptor,  object  value)
         {
             base .SetProperty(controllerContext,bindingContext, propertyDescriptor, value);
             foreach (ModelValidator modelValidator  in  ModelValidatorProviders.Providers.GetValidators(bindingContext.PropertyMetadata[propertyDescriptor.Name],controllerContext))
             {
                 IEnumerable<ModelValidationResult> modelValidationResults =modelValidator.Validate(value);
                 foreach (ModelValidationResult modelValidationResultin modelValidationResults)
                 {
                    bindingContext.ModelState.AddModelError(modelValidationResult.MemberName,modelValidationResult.Message);
                 }
             }
  
         }
         protectedoverride voidOnModelUpdated(ControllerContextcontrollerContext, ModelBindingContextbindingContext)
         {
             //base.OnModelUpdated(controllerContext,bindingContext);
             foreach (ModelValidator modelValidator  in  ModelValidatorProviders.Providers.GetValidators(bindingContext.ModelMetadata,controllerContext))
             {
                 IEnumerable<ModelValidationResult> modelValidationResults =modelValidator.Validate( null );
                 foreach (ModelValidationResult modelValidationResultin modelValidationResults)
                 {
                     bindingContext.ModelState.AddModelError(modelValidationResult.MemberName,modelValidationResult.Message);
                 }
             }
         }
     }


有了代码1-7中的Model绑定器就可以吻合我们前面所定义的Model验证器以及提供程序了。

我要把MyCustomModelValidatorProvider类型和MyCustomModelValidatorDefaultModelBinder类型注册到系统中,将示例代码1-8部分添加至Global.asax文件的Application_Start()方法中。

代码1-8

1
2
ModelBinders.Binders.Add( typeof (Models.RegistrationInformation), newBinders.MyCustomModelValidatorDefaultModelBinder());
ModelValidatorProviders.Providers.Insert(0, newModelValidators.MyCustomModelValidatorProvider());


看下图1,图1为初始的展示页面,图2为图1中点击提交后执行验证过后。

1

wKiom1PD0VXzie6XAAEJrDFD7Mw021.jpg

2

wKioL1PD0TfzgIHTAAHA1OkfjUQ569.jpg







     本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1438118,如需转载请自行联系原作者





相关文章
|
前端开发 .NET 数据安全/隐私保护
菜鸟入门【ASP.NET Core】15:MVC开发:ReturnUrl实现、Model后端验证 、Model前端验证
ReturnUrl实现 我们要实现returnUrl,我们需要在注册(Register)方法中接收传进的returnUrl并给它默认值null,然后将它保存在ViewData里面 然后我们定义一个内部方法来判断跳转returnUrl //内部跳转 private IActionR...
2445 0
|
9月前
|
开发框架 JSON 算法
ASP.NET Core Web API之Token验证
ASP.NET Core Web API之Token验证
145 0
|
XML 开发框架 JSON
ASP.NET Core - 实现自定义WebApi模型验证
ASP.NET Core - 实现自定义WebApi模型验证  Framework时代    在Framework时代,我们一般进行参数验证的时候,以下代码是非常常见的 复制代码 [HttpPost] public async Task<JsonResult> SaveNewCus...
1663 0
|
开发框架 前端开发 JavaScript
ASP.NET Core MVC 之模型(Model)
ASP.NET Core MVC 之模型(Model)  1.模型绑定   ASP.NET Core MVC 中的模型绑定将数据从HTTP请求映射到操作方法参数。参数既可以是简单类型,也可以是复杂类型。
1137 0
ASP.NET Core微服务之基于Ocelot+IdentityServer实现统一验证与授权
Tip: 此篇已加入.NET Core微服务基础系列文章索引 一、案例结构总览   这里,假设我们有两个客户端(一个Web网站,一个移动App),他们要使用系统,需要通过API网关(这里API网关始终作为客户端的统一入口)先向IdentityService进行Login以进行验证并获取Token,在IdentityService的验证过程中会访问数据库以验证。
2705 0
|
前端开发
4.ASP.NET全栈开发之在MVC中使用服务端验证(二)
首先声明,这篇博文是完善.ASP.NET全栈开发之在MVC中使用服务端验证 的,所以重复内容,我就不过多的阐述,很多问题都是在实践中去发现,然后再去完善,这篇博文也一样,建立在已阅 “.ASP.NET全栈开发之在MVC中使用服务端验证” 的基础上。
1219 0
|
前端开发 UED .NET
2.ASP.NET全栈开发之在MVC中使用服务端验证
上一章我们在控制台中基本的了解了FluentValidation是如何简洁,优雅的完成了对实体的验证工作,今天我们将在实战项目中去应用它。 首先我们创建一个ASP.NET MVC项目,本人环境是VS2017, 创建成功后通过在Nuget中使用 Install-Package FluentValidation -Version 7.
1106 0