ASP.NET MVC采用Model绑定为目标Action生成了相应的参数列表,但是在真正执行目标Action方法之前,还需要对绑定的参数实施验证以确保其有效 性,我们将针对参数的验证成为Model绑定。总地来说,我们可以采用4种不同的编程模式来进行针对绑定参数的验证。

目录

一、手工验证绑定的参数
二、使用ValidationAttribute特性
三、让数据类型实现IValidatableObject接口
四、让数据类型实现IDataErrorInfo接口

一、手工验证绑定的参数


定义具体Action方法的时候,对已经成功绑定的参数实施手工验证无疑是一种最为直接的编程方式,接下来我们通过一个简单的实例来演示如何将参数验证逻
辑实现在对应的Action方法中,并在没有通过验证的情况下将错误信息响应给客户端。我们在一个ASP.NET
MVC应用中定义了如下一个Person类作为被验证的数据类型,它的Name、Gender和Age三个属性分别表示一个人的姓名、性别和年龄。

1: public class Person

   3:     [DisplayName("姓名")]
   4:     public string Name { get; set; }
   5:  
   7:     public string Gender { get; set; }
   8:  
  10:     public int? Age { get; set; }
   2: {
   4:     public ActionResult Index()
   6:         return View(new Person());
   8:  
  10:     public ActionResult Index(Person person)
  12:         Validate(person);
  13:  
  15:         {
  16:             return View(person);
  18:         else
  20:             return Content("输入数据通过验证");
  22:     }
  23:  
  25:     {
  27:         {
  28:             ModelState.AddModelError("Name", "'Name'是必需字段");
  30:  
  32:         {
  33:             ModelState.AddModelError("Gender", "'Gender'是必需字段");
  35:         else if (!new string[] { "M", "F" }.Any(g => string.Compare(person.Gender, g, true) == 0))
  37:             ModelState.AddModelError("Gender", "有效'Gender'必须是'M','F'之一");
  39:  
  41:         {
  42:             ModelState.AddModelError("Age", "'Age'是必需字段");
  44:         else if (person.Age > 25 || person.Age < 18)
  46:             ModelState.AddModelError("Age", "有效'Age'必须在18到25周岁之间");
  48:     }
  49: }

如上面的代码片断所示,我们在Validate该方法中我们对作为参数的Person对象的3个属性进行逐条验证,如果提供的数据没有通过验证,我 们会调用当前ModelState的AddModelError方法将指定的验证错误消息转换为ModelError保存起来。我们采用的具体的验证规则 如下。

  • Person对象的Name、Gender和Age属性均为必需字段,不能为Null(或者空字符串)。
  • 表示性别的Gender属性的值必需是“M”(Male)或者“F”(Female),其余的均为无效值。
  • Age属性表示的年龄必须在18到25周岁之间。

如下所示的是Action方法Index对应View的定义,这是一个Model类型为Person的强类型View,它包含一个用于编辑人员信息 的表单。我们直接调用HtmlHelper<TModel> 的扩展方法EditorForModel将作为Model的Person对象以编辑模式呈现在表单之中。

1: @model Person

html>
head>
title>编辑人员信息</title>
head>
body>
   8:     @using (Html.BeginForm())
  10:         <div>@Html.LabelFor(m=>m.Name)</div>
div>@Html.EditorFor(m=>m.Name)</div>
  13:         <div>@Html.LabelFor(m=>m.Gender)</div>
div>@Html.EditorFor(m => m.Gender)</div>
  16:         <div>@Html.LabelFor(m=>m.Age)</div>
div>@Html.EditorFor(m => m.Age)</div>
  19:         <input type="submit" value="保存"/>
  21: </body>
html>

直接运行该程序后,一个用于编辑人员基本信息的页面会被呈现出来,如果我们在输入不合法的数据并提交后,相应的验证信息会以图1所示的形式呈现出来。

二、使用ValidationAttribute特性

将针对输入参数的验证逻辑和业务逻辑定义在Action方法中并不是一种值得推荐的编程方式。在大部分情况下,同一个数据类型在不同的应用场景中具 有相同的验证规则,如果我们能将验证规则与数据类型关联在一起,让框架本身来实施数据验证,那么最终的开发者就可以将关注点更多地放在业务逻辑的实现上 面。实际上这也是ASP.NET MVC的Model验证系统默认支持的编程方式。当我们在定义数据类型的时候,可以在类型及其数据成员上面应用相应的 ValidationAttribute特性来定义默认采用的验证规则。

“System.ComponentModel.DataAnnotations”命名空间定义了一系列具体的 ValidationAttribute特性类型,它们大都可以直接应用在自定义数据类型的某个属性上对目标数据成员实施验证。这些预定义验证特性不是本 章论述的重点,我们会在“下篇”中对它们作一个概括性的介绍。

常规验证可以通过上面列出的这些预定义ValidationAttribute特性来完成,但是在很多情况下我们需要通过创建自定义的 ValidationAttribute特性来解决一些特殊的验证。比如上面演示实例中针对Person对象的验证中,我们要求Gender属性指定的表 示性别的值必须是“M/m”和“F/f”两者之一,这样的验证就不得不通过自定义的ValidationAttribute特性来实现。

针对 “某个值必须在指定的范围内”这样的验证规则,我们定义一个DomainAttribute特性。如下面的代码片断所示,DomainAttribute 具有一个IEnumerable<string>类型的只读属性Values提供了一个有效值列表,该列表在构造函数中被初始化。具体的验证 实现在重写的IsValid方法中,如果被验证的值在这个列表中,则视为验证成功并返回True。为了提供一个友好的错误消息,我们重写了方法 FormatErrorMessage。

1: [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]

   3: {
string> Values { get; private set; }
   5:  
   7:     {
   8:         this.Values = new string[] { value };
  10:  
  12:     {
  13:         this.Values = values;
  15:  
  17:     {
  19:         {
  20:             return true;
  22:         return this.Values.Any(item => value.ToString() == item);
  24:  
  26:     {
string.Format("'{0}'",value)).ToArray();
  28:         return string.Format(base.ErrorMessageString, name,string.Join(",", values));
  30: }

由于ASP.NET MVC在进行参数绑定的时候会自动提取应用在目标参数类型或者数据成员上的ValidationAttribute特性,并利用它们对提供的数据实施验 证,所以我们不再需要像上面演示的实例一样自行在Action方法中实施验证,而只需要在定义参数类型Person的时候应用相应的 ValidationAttribute特性将采用的验证规则与对应的数据成员相关联。如下所示的是属性成员上应用了相关 ValidationAttribute特性的Person类型的定义。我们在三个属性上均应用了RequiredAttribute特性将它们定义成必 需的数据成员,Gender和Age属性上则分别应用了DomainAttribute和RangeAttribute特性对有效属性值的范围作了相应限 制。

1: public class Person

   3:     [DisplayName("姓名")]
   5:     public string Name { get; set; }
   6:  
   8:     [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources))]
  10:     public string Gender { get; set; }
  11:  
  13:     [Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources))]
  15:     public int? Age { get; set; }

三个ValidationAttribute特性采用的错误消息均定义在项目默认的资源文件中(我们可以采用这样的步骤创建这个资源文件:右键选择 Solution Exploror中的项目,并在上下文菜单中选择“属性”选项打开“项目属性”对象框。最后在对话框中选择“资源”Tab页面,通过点击页面中的链接创建 一个资源文件),具体定义如图2所示。

由于ASP.NET MVC会自动提取应用在绑定参数类型上的ValidationAttribute特性对绑定的参数实施自动化验证,所以我们根本不需要在具体的 Action方法中来对参数作手工验证。如下面的代码片断所示,我们在Action方法Index中不再显式调用Validate方法,但是运行该程序并 在输入不合法数据的情况下提交表单后依然会得到如图1所示的输出结果。

1: public class HomeController : Controller

   3:     //其他成员
   5:     public ActionResult Index(Person person)
   7:         if (!ModelState.IsValid)
   9:             return View(person);
  11:         else
  13:             return Content("输入数据通过验证");
  15:     }
   2: {
   3:     IEnumerable<ValidationResult> Validate(ValidationContext validationContext);
   2: {
   4:     public string Name { get; set; }
   5:  
   7:     public string Gender { get; set; }
   8:  
  10:     public int? Age { get; set; }
  11:  
  12:     public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
  14:         Person person = validationContext.ObjectInstance as Person;
  16:         {
  17:             yield break;
  19:         if(string.IsNullOrEmpty(person.Name))
  21:             yield return new ValidationResult("'Name'是必需字段", new string[]{"Name"});
  23:  
  25:         {
  26:             yield return new ValidationResult("'Gender'是必需字段", new string[] { "Gender" });
  28:         else if (!new string[]{"M","F"}.Any(g=>string.Compare(person.Gender,g, true) == 0))
  30:             yield return new ValidationResult("有效'Gender'必须是'M','F'之一", new string[] { "Gender" });
  32:  
  34:         {
  35:             yield return new ValidationResult("'Age'是必需字段", new string[] { "Age" });
  37:         else if (person.Age > 25 || person.Age < 18)
  39:             yield return new ValidationResult("'Age'必须在18到25周岁之间", new string[] { "Age" });
  41:     }
   2: {
   3:     string Error { get; }
   4:     string this[string columnName] { get; }
   1: public class Person : IDataErrorInfo
   3:     [DisplayName("姓名")]
   4:     public string Name { get; set; }
   5:  
   7:     public string Gender { get; set; }
   8:  
  10:     public int? Age { get; set; }
  11:  
  13:     public string Error { get; private set; }
  14:  
  16:     {
  18:         {
  20:             {
  22:                     { 
  24:                         {
  25:                             return "'姓名'是必需字段";
  27:                         return null;
  29:                 case "Gender":
  31:                         if (string.IsNullOrEmpty(this.Gender))
  33:                             return "'性别'是必需字段";
  35:                         else if (!new string[] { "M", "F" }.Any(g => string.Compare(this.Gender, g, true) == 0))
  37:                             return "'性别'必须是'M','F'之一";
  39:                         return null;
  41:                 case "Age":
  43:                         if (null == this.Age)
  45:                             return "'年龄'是必需字段";
  47:                         else if (this.Age > 25 || this.Age < 18)
  49:                             return "'年龄'必须在18到25周岁之间";
  51:                         return null;
  53:                 default: return null;
  55:             }
  57:     }
  58: }

下一篇 ASP.NET MVC下的四种验证编程方式[续篇]
原文:http://www.cnblogs.com/artech/p/asp-net-mvc-validation-programming.html

ASP.NET MVC下的四种验证编程方式【转】的更多相关文章

  1. ASP.NET MVC下的四种验证编程方式[续篇]

    在<ASP.NET MVC下的四种验证编程方式>一文中我们介绍了ASP.NET MVC支持的四种服务端验证的编程方式("手工验证"."标注Validation ...

  2. ASP.NET MVC下的四种验证编程方式

    ASP.NET MVC采用Model绑定为目标Action生成了相应的参数列表,但是在真正执行目标Action方法之前,还需要对绑定的参数实施验证以确保其有效性,我们将针对参数的验证成为Model绑定 ...

  3. ASP.NET MVC下的四种验证编程方式[续篇]【转】

    在<ASP.NET MVC下的四种验证编程方式> 一文中我们介绍了ASP.NET MVC支持的四种服务端验证的编程方式(“手工验证”.“标注ValidationAttribute特性”.“ ...

  4. Asp.Net Core下的两种路由配置方式

    与Asp.Net Mvc创建区域的时候会自动为你创建区域路由方式不同的是,Asp.Net Core下需要自己手动做一些配置,但更灵活了. 我们先创建一个区域,如下图 然后我们启动访问/Manage/H ...

  5. 在ASP.NET MVC下扩展一个带验证的RadioButtonList

    在ASP.NET MVC4中,HtmlHelper为我们提供了Html.RadioButton()方法用来显示Radio Button单选按钮.如果想显示一组单选按钮,通常的做法是遍历一个集合把每个单 ...

  6. ASP.NET MVC 主要的四种过滤器和三种具体实现类

    4种常用过滤器(IAuthrorizationFilter.IActionFilter.IResultFilter.IExceptionFilter) 和 3种具体实现类(AuthorizeAttri ...

  7. 待实践二:MVC3下的3种验证 (1)前台 jquery validate验证 (2)MVC实体验证 (3)EF生成的/自己手写的 自定义实体校验(伙伴类+元素据共享)

    MVC3下的3种验证 (1):前台Jquery Validate脚本验证 引入脚本 <script src="../js/jquery.js" type="text ...

  8. ASP.NET MVC Model元数据(四)

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

  9. SNF快速开发平台MVC-EasyUI3.9之-ueditor富文本编辑在 asp.net MVC下使用步骤

    mvc项目中用到了这个富文本编辑就试着把遇到的问题个使用步骤在这里记录一下,希望大家少走弯路. 1.首先我们先下载net版本的uediot 2.然后把整个文档拷贝到我们的项目中,记得是整个 把下载的文 ...

随机推荐

  1. you need to upgrade the working copy first

    is too old (format 29) to work with client version '1.9.4 (r1740329)' (expects format 31) 2016年09月18 ...

  2. ARC机制集合内存管理

    // //  main.m //  13-ARC机制集合内存管理 // //  Created by apple on 14-3-21. //  Copyright (c) 2014年 apple. ...

  3. Basic认证

    Basic 概述 Basic 认证是HTTP 中非常简单的认证方式,因为简单,所以不是很安全,不过仍然非常常用. 当一个客户端向一个需要认证的HTTP服务器进行数据请求时,如果之前没有认证过,HTTP ...

  4. Java基础之线程——使用Runnable接口(JumbleNames)

    控制台程序. 除了定义Thread新的子类外,还可以在类中实现Runnable接口.您会发现这比从Thread类派生子类更方便,因为在实现Runnable接口时可以从不是Thread的类派生子类,并且 ...

  5. Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-2 创建熊猫类

    当我们创建好项目文件后我们就可以开始一步一步的按照我们之前列入的清单来编写我们的游戏.现在就让我们来创建一个熊猫这个类Panda.swift.我们将采取分解的方式,一步一步的完成Panda.swift ...

  6. Leetcode: Remove Elements

    Given an array and a value, remove all instances of that value in place and return the new length. T ...

  7. Topcoder SRM 598 div2

    e,不知道为啥进不去了,这个B题贪心,从最小和最大的匹配如果超过了就只去最大的! 然后就没了- -! 这场比赛时不知为啥,string出问题了,可能是编译器挂了!0蛋- -!

  8. Codeforce Round #215 Div2 C

    还以为就这么点分了,不会跪了,起码有点加,生活都这么艰难了,为什么不让我好好地活下去! 是不是世界对我充满了恶意! 当然还是自己太菜! B题没初始化第一个就杯具了一次 C题大概的弄出来了,调了半个小时 ...

  9. GC是什么? 为什么要有GC?

    GC是什么? 为什么要有GC?  GC是垃圾收集器.  程序员不用担心内存管理,因为垃圾收集器会自动进行管理.要请求垃圾收集,可以调用下面的方法之一:  System.gc() Runtime.get ...

  10. LED流水灯(二)

    记住看汇编的时候是红在上面 黑色在下面 startup.s 程序 ; MDK跑马灯实验; PRESERVE8               // 字节对齐关键词 ,汇编有8位对齐的要求,要添加 AREA ...