ASP.NETMVC Model验证(四)

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

    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

    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

    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

    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()方法中调用的,所以上述可以直接通过Metadata的Model属性直接获取Model的值,由此来进行验证,而这句ControllerContext.Controller.TempData.ContainsKey("Password1")代码的含义是判断在Model的Password1属性在属性级验证的时候是否通过了,因为每个Model验证器之间无法传递消息,只有ControllerContext是指向一个引用的,所有用它来做数据信息的承载。在代码1-3中已经定义了。(对于第二部分的理解不太明白的朋友可以结合上篇和本篇来看)

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

代码1-5

    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级验证时对Model的Name属性进行验证。

ModelValidatorProvider

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

代码1-6

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

    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

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

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

图1

图2

ASP.NETMVC Model验证(四),布布扣,bubuko.com

时间: 2024-10-06 01:19:56

ASP.NETMVC Model验证(四)的相关文章

ASP.NET MVC Model验证(四)

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

一篇关于Asp.Net Model验证响应消息的问题处理

之前,我做过Asp.Net Core的Model验证,在Core中过滤器对响应的处理很简单 context.Result = new JsonResult(ErrorMsg); 但是,在Asp.Net中context是没有Result这个属性的,只有一个Response属性可以对响应结果进行处理 context.Response=new HttpResponseMessage(statusCode: HttpStatusCode.OK) { Content = new StringContent

ASP.NET MVC Model元数据(四)

ASP.NET MVC Model元数据(四) 前言 前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释.看完本篇后将会对Model元数据有更清楚的了解,当然了也不会是特别全面的,因为后面还有篇幅.希望能给大家带来好的效果. Model元数据 什么是Model元数据? 生成Model元数据的过程[一] 生成Model元数据的过程[二] ModelMetaData的定义.详解 Model元数据应用(常用特性应用)-1 Model元数据

ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上

原文:ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上 ASP.NET MVC默认采用基于标准特性的Model验证机制,但是只有应用在Model类型及其属性上的ValidationAttribute才有效.如果我们能够将ValidationAttribute特性直接应用到参数上,我们不但可以实现简单类型(比如int.double等)数据的Model验证,还能够实现“一个Model类型,多种验证规则”,本篇文章将为你提供相关的解决方案(源代码

ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则

原文:ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则 对于Model验证,理想的设计应该是场景驱动的,而不是Model(类型)驱动的,也就是对于同一个Model对象,在不同的使用场景中可能具有不同的验证规则.举个简单的例子,对于一个表示应聘者的数据对象来说,针对应聘的岗位不同,肯定对应聘者的年龄.性别.专业技能等方面有不同的要求.但是ASP.NET MVC的Model验证确是Model驱动的,因为验证规则以验证特性的形式应用到Model类型及其属性上.这样的验证

ASP.NET MVC Model验证(二)

ASP.NET MVC Model验证(二) 前言 上篇内容演示了一个简单的Model验证示例,然后在文中提及到Model验证在MVC框架中默认所处的位置在哪?本篇就是来解决 这个问题的,并且会描述一下ModelValidator类型对象相关的类型. Model验证 Model验证简单运用示例 ModelValidator使用生成过程 自定义实现DefaultModelBinder进行验证 自定义ModelValidatorProvider 和ModelValidator  Validation

ASP.NET MVC Model验证(一)

ASP.NET MVC Model验证(一) 前言 前面对于Model绑定部分作了大概的介绍,从这章开始就进入Model验证部分了,这个实际上是一个系列的Model的绑定往往都是伴随着验证的.也会在后面的篇幅中讲解MVC框架中Model验证的机制,以及一些Model验证的方式讲解,本章只是一个简单的示例篇幅,对于有基础的朋友可以直接跳过了(不能耽误大家时间). Model验证 Model验证简单运用示例 ModelValidator使用生成过程 自定义实现DefaultModelBinder进行

ASP.NET MVC Model验证(三)

ASP.NET MVC Model验证(三) 前言 上篇中说到在MVC框架中默认的Model验证是在哪里验证的,还讲到DefaultModelBinder类型的内部执行的示意图,让大家可以看到默认的Model验证是在哪个具体的方法中来执行的,本篇的主题就是模拟一下默认的实现,自定义个Model绑定器继承自DefaultModelBinder类型,并且重写某些个重要的方法. Model验证 Model验证简单运用示例 ModelValidator使用生成过程 自定义实现DefaultModelBi

ASP.NET MVC Model验证学习—上

蒋大师的MVC框架解析确实是越学越有趣,即使是跟着学写些示例代码也是收获良多,尤其是关于类型.反射和委托等方面,平时在应用开发中确实很少会有机会写这样的代码.今天学习的ASP.NET MVC中的Model的验证,刚开时会以为这一章会比较简单,因为之前已经学习过了Model元数据的解析.Model绑定,Model的验证可能就只是DataAnnotation相关类的介绍.但实际学习的过程中,尤其是自定义用于修饰Action的验证特性让我到现在仍然感觉是比较萌萌哒,毕竟这一块对于框架的扩展基本上涉及到