博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET MVC Model验证(四)
阅读量:5758 次
发布时间:2019-06-18

本文共 12113 字,大约阅读时间需要 40 分钟。

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

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

代码1-2

public class ModelValidationResult    {        public ModelValidationResult();        // 摘要:        //     获取或设置成员名。        //        // 返回结果:        //     成员名。        public string MemberName { get; set; }        //        // 摘要:        //     获取或设置验证结果消息。        //        // 返回结果:        //     验证结果消息。        public string Message { get; set; }    }

 

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

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

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

代码1-3

public class MyCustomModelPropertyValidator : ModelValidator    {        public MyCustomModelPropertyValidator(ModelMetadata modelMetadata, ControllerContext controllContext)            : base(modelMetadata, controllContext)        { }        public override IEnumerable
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": return Enumerable.Empty
(); } return Enumerable.Empty
(); } }

 

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

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

代码1-4

public class MyCustomModelPassWordValidator : ModelValidator    {        public MyCustomModelPassWordValidator(ModelMetadata modelMetadata, ControllerContext controllerContext)            : base(modelMetadata, controllerContext)        { }        public override IEnumerable
Validate(object container) { Models.RegistrationInformation regInfo = 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="请重新输入密码,与上次输入密码不同!" } }; } } } return Enumerable.Empty
(); } }

 

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

 

代码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
GetValidators(ModelMetadata metadata, ControllerContext context) { if (metadata.ContainerType == typeof(Models.RegistrationInformation)) { return new ModelValidator[] { new MyCustomModelPropertyValidator(metadata,context) }; } else if (metadata.ModelType == typeof(Models.RegistrationInformation)) { return new ModelValidator[] { new MyCustomModelPassWordValidator(metadata,context), new MyCustomModelNameValidator(metadata,context) }; } return Enumerable.Empty
(); } }}

 

在代码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    {        protected override void SetProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value)        {            base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);            foreach (ModelValidator modelValidator in ModelValidatorProviders.Providers.GetValidators(bindingContext.PropertyMetadata[propertyDescriptor.Name], controllerContext))            {                IEnumerable
modelValidationResults = modelValidator.Validate(value); foreach (ModelValidationResult modelValidationResult in modelValidationResults) { bindingContext.ModelState.AddModelError(modelValidationResult.MemberName, modelValidationResult.Message); } } } protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) { //base.OnModelUpdated(controllerContext, bindingContext); foreach (ModelValidator modelValidator in ModelValidatorProviders.Providers.GetValidators(bindingContext.ModelMetadata, controllerContext)) { IEnumerable
modelValidationResults = modelValidator.Validate(null); foreach (ModelValidationResult modelValidationResult in 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), new Binders.MyCustomModelValidatorDefaultModelBinder());ModelValidatorProviders.Providers.Insert(0, new ModelValidators.MyCustomModelValidatorProvider());

 

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

图1

图2

 

作者:

出处:

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面

转载于:https://www.cnblogs.com/jin-yuan/p/3843411.html

你可能感兴趣的文章
如何通过解决精益问题提高敏捷团队生产力
查看>>
阿里云数据库产品总监何云飞:云服务是影响未来10~20年的事
查看>>
Comment2Wechat —— Typecho 插件
查看>>
Apache下.htaccess文件配置及功能介绍
查看>>
Magento XML cheatsheet
查看>>
Egg 2.19.0 发布,阿里开源的企业级 Node.js 框架
查看>>
SegmentFault for Android —— 夜晚中的思考者
查看>>
sap的function module发布成web service后fm再次修改的处理 ...
查看>>
Kubernetes 弹性伸缩全场景解析 (四)- 让核心组件充满弹性 ...
查看>>
使用MySQLTuner-perl对MySQL进行优化
查看>>
ubuntu18.10手动安装mysql5.5
查看>>
SAP S/4HANA extensibility扩展原理介绍
查看>>
Swoole 4.1.0 正式版发布,支持原生 Redis/PDO/MySQLi 协程化 ...
查看>>
开发网络视频直播系统需要注意的地方
查看>>
haproxy mysql实例配置
查看>>
强化学习的未来— 第一部分
查看>>
掌握Python系统管理-调试和分析脚本1-debugging
查看>>
TableStore:用户画像数据的存储和查询利器
查看>>
2019 DockerCon 大会即将召开,快来制定您的专属议程吧!
查看>>
15分钟构建超低成本数据大屏:DataV + DLA
查看>>