ASP.NET MVC Model验证(四)

时间:2022-09-21 21:30:35

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<ModelClientValidationRule> GetClientValidationRules();
public static ModelValidator GetModelValidator(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
{
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<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":
return Enumerable.Empty<ModelValidationResult>(); }
return Enumerable.Empty<ModelValidationResult>();
}
}

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

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

图1

ASP.NET MVC Model验证(四)

图2

ASP.NET MVC Model验证(四)

作者:金源

出处:http://www.cnblogs.com/jin-yuan/

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

ASP.NET MVC Model验证(四)的更多相关文章

  1. ASP&period;NET MVC Model元数据&lpar;四&rpar;

    ASP.NET MVC Model元数据(四) 前言 前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释.看完本篇后将会对Model元数 ...

  2. 详解ASP&period;NET MVC Model验证

    ASP.NET mvc的最好的优点之一就是支持Model验证,这个特性很方便你可以选择在定义Model的时候在字段中采用特性进行注解约定,也可以在代码中自己进行手动验证.下面就来细说一下ASP.NET ...

  3. ASP&period;NET MVC Model验证&lpar;五&rpar;

    ASP.NET MVC Model验证(五) 前言 上篇主要讲解ModelValidatorProvider 和ModelValidator两种类型的自定义实现, 然而在MVC框架中还给我们提供了其它 ...

  4. ASP&period;NET MVC Model验证&lpar;三&rpar;

    ASP.NET MVC Model验证(三) 前言 上篇中说到在MVC框架中默认的Model验证是在哪里验证的,还讲到DefaultModelBinder类型的内部执行的示意图,让大家可以看到默认的M ...

  5. ASP&period;NET MVC Model验证&lpar;二&rpar;

    ASP.NET MVC Model验证(二) 前言 上篇内容演示了一个简单的Model验证示例,然后在文中提及到Model验证在MVC框架中默认所处的位置在哪?本篇就是来解决这个问题的,并且会描述一下 ...

  6. ASP&period;NET MVC Model验证&lpar;一&rpar;

    ASP.NET MVC Model验证(一) 前言 前面对于Model绑定部分作了大概的介绍,从这章开始就进入Model验证部分了,这个实际上是一个系列的Model的绑定往往都是伴随着验证的.也会在后 ...

  7. ASP&period;NET MVC Model绑定&lpar;四&rpar;

    ASP.NET MVC Model绑定(四) 前言 前面的篇幅对于Model绑定器IModelBinder以及实现类型.Model绑定器提供程序都作了粗略的讲解,可以把Model绑定器想象成一个大的容 ...

  8. 【转】【Asp&period;Net MVC】asp&period;net mvc Model验证总结及常用正则表达式

    本文属转载,来源: http://www.byywee.com/page/M0/S868/868615.html 关于Model验证官方资料: http://msdn.microsoft.com/zh ...

  9. 【Asp&period;Net MVC】asp&period;net mvc Model验证总结及常用正则表达式

    转自:http://www.cnblogs.com/easy5weikai/p/3843131.html 关于Model验证官方资料: http://msdn.microsoft.com/zh-cn/ ...

随机推荐

  1. 【转】C&num; 控件的自定义拖动、改变大小方法

    在用VS的窗体设计器时,我们可以发现控件都是可以拖动的,并且还可以调整大小.怎么在自己的程序中可以使用上述功能呢? 下面的方法值得借鉴! using System; using System.Wind ...

  2. Front End Developer Questions 前端开发人员问题(二)

    问题来源:http://markyun.github.io/2015/Front-end-Developer-Questions/ 二.CSS 1.介绍一下标准的CSS的盒子模型?与低版本IE的盒子模 ...

  3. Codeforces 600B Queries about less or equal elements&lpar;二分查找&rpar;

    Description You are given two arrays of integers a and b. For each element of the second array bj yo ...

  4. java createSQLQuery&lpar;&rpar;&period;list&lpar;&rpar;返回日期格式没有时分秒的解决方法

    方法一 将Oracel数据库对应表中“收单时间的字段”receive_sheet_time,由原来的Date类型改为timestamp 然后,在java程序中,由 (java.util.timesta ...

  5. -&lowbar;-&num;【Canvas】回弹

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. 在不同编译环境中如何使用sleep()函数

    今天在学习有关时间函数时,想让程序暂时挂起,一段时间后在继续执行! 用到了系统函数sleep(): 在vc下sleep函数是以毫秒为单位,如果想让其停留3秒,需要这样做  sleep(3*1000); ...

  7. ajax请求后台,有时收不到返回值的解决办法

    昨天下午做项目遇到一个问题,贴出来方便以后翻阅,也给大家个参考. 问题: 具体做的是个文件导入的功能,导入的功能是成功了,但是界面一直得不到返回值,排查了一下午,调试的时候是可以有返回的,但是关掉浏览 ...

  8. HTML标签嵌套规则

    摘要:  最近在整理项目时发现有些同事写的页面代码嵌套的太多,而且有些嵌套不对,比如<a><div>内容</div></a>.虽然功能实现了,但是对于浏 ...

  9. PAT 1012 数字分类 C语言

    给定一系列正整数,请按要求对数字进行分类,并输出以下5个数字: A1 = 能被5整除的数字中所有偶数的和: A2 = 将被5除后余1的数字按给出顺序进行交错求和,即计算n1-n2+n3-n4...: ...

  10. 关于js中的取值问题

    像这样是获取不到值的,弹出的消息是 underfined:<html><style type="text/css">input { border: 1px ...