使用VisualStudio2010和MVC2.0增强验证功能

在开始之前,我不得不说明我已经安装了Visual Studio 2010 RC1,并使用它将老版本转换为ASP.Net 4.0,大多数情况下,当你接收到来自用户从form表单post来的信息后,你的验证代码往往会检查相应的值是否存在,数据类型是否正确以及数据的范围是否正确。

创新互联公司:成立于2013年为各行业开拓出企业自己的“网站建设”服务,为1000多家公司企业提供了专业的成都网站设计、成都网站建设、网页设计和网站推广服务, 按需定制由设计师亲自精心设计,设计的效果完全按照客户的要求,并适当的提出合理的建议,拥有的视觉效果,策划师分析客户的同行竞争对手,根据客户的实际情况给出合理的网站构架,制作客户同行业具有领先地位的。

如果将验证代码放到一个集中的地方时,那类似上面所说的改变会不会变得更简单些?Model中的DataAnnotations正是为此而来,在MVC 2.0中,这一特性被包含在内。

DataAnnotations作为.net Framework的一部分已经有一段时间了,但是MVC 2.0中增加了ModelMetaData类,这是储存MetaData的容器,默认会使用同样也是新增类的DataAnnotationsMetaDataProvider类。因为传入的值会由Action方法接受model binding作为匹配传入参数和action的参数而介入。

在MVC 2.0中,默认的model binder使用DataAnnotationsMetaDataProvider来获取metadata中model binder尝试匹配的对象,如果验证用的metadata存在,则其会通过对对象的属性和传入的值比较来进验证,这类meta由你通过使用标签(Attribute)修饰属性来实现。

下面例子中我通过原程序中添加联系人这一过程来描述使用DataAnnotatioins的方法,这里我们使用自定义ViewModel,名为:ContactPersonViewModel。通过Contact.Add()这个action方法来添加联系人,代码如下:

 
 
 
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Web.Mvc;  
  4. using System.ComponentModel;  
  5.  
  6. namespace ContactManagerMVC.Views.ViewModels  
  7. {  
  8.   public class ContactPersonViewModel  
  9.   {  
  10.     public int Id { get; set; }  
  11.     public string FirstName { get; set; }  
  12.     public string MiddleName { get; set; }  
  13.     public string LastName { get; set; }  
  14.     public DateTime DateOfBirth { get; set; }  
  15.     public IEnumerable Type { get; set; }  
  16.   }  
  17. }  

下面,我在为属性添加一些标签(Attribute):

 
 
 
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Web.Mvc;  
  4. using System.ComponentModel.DataAnnotations;  
  5. using ContactManagerMVC.Attributes;  
  6. using System.ComponentModel;  
  7.  
  8. namespace ContactManagerMVC.Views.ViewModels  
  9. {  
  10.   public class ContactPersonViewModel  
  11.   {  
  12.     public int Id { get; set; }  
  13.     [Required(ErrorMessage = "Please provide a First Name!")]  
  14.     [StringLength(25, ErrorMessage = "First name must be less than 25 characters!")]  
  15.     [DisplayName("First Name")]  
  16.     public string FirstName { get; set; }  
  17.  
  18.     [DisplayName("Middle Name")]  
  19.     public string MiddleName { get; set; }  
  20.  
  21.     [Required(ErrorMessage = "Please provide a Last Name!")]  
  22.     [StringLength(25, ErrorMessage = "Last name must be less than 25 characters!")]  
  23.     [DisplayName("Last Name")]  
  24.     public string LastName { get; set; }  
  25.  
  26.     [Required(ErrorMessage = "You must provide a Date Of Birth!")]  
  27.     [BeforeTodaysDate(ErrorMessage = "You can't add someone who hasn't been born yet!")]  
  28.     [DisplayName("Date Of Birth")]  
  29.     public DateTime? DateOfBirth { get; set; }  
  30.  
  31.     public IEnumerable Type { get; set; }  
  32.   }  
  33. }  

上面标签的绝大多数标签都是在System.ComponentModel.Annotations命名空间内,只有RequiredAttribute标签不在此命名空间内,这个标签声明此值必须是一个有效值,并且包含ErrorMessage属性。这个属性可以让你传入自定义错误信息。StringLengthAttribute标签指定了属性可以接受的最小值和***值范围。当和RequiredAttribute标签结合使用时,只需要设置可以接受的***值。DisplayNameAttribute用于设置属性如何显示。#p#

上面标签中BeforeTodaysDateAttribute标签并不是.net Framework所提供,这是一个自定义标签,用于检测日期是否比当前的日期要早,你可以看到ErrorMessage值被设置。这个标签用于防止任何被添加到联系人列表的联系人还未出生,下面是这个标签的代码:

 
 
 
 
  1. using System.ComponentModel.DataAnnotations;  
  2. using System;  
  3.  
  4. namespace ContactManagerMVC.Attributes  
  5. {  
  6.   public class BeforeTodaysDateAttribute : ValidationAttribute  
  7.   {  
  8.     public override bool IsValid(object value)  
  9.     {  
  10. if (value == null)  
  11. {  
  12.   return true;  
  13. }  
  14. DateTime result;  
  15. if (DateTime.TryParse(value.ToString(), out result))  
  16. {  
  17.   if (result < DateTime.Now)  
  18.   {  
  19.     return true;  
  20.   }  
  21. }  
  22. return false;  
  23.     }  
  24.   }  
  25. }  

很简单是吧,这个类继承了ValidationAttribute并重写了IsValid()虚方法,如果未提供值,或是值小于当前日期(DateTime.Now),则返回True.利用标签(Attribute)的方式让在一个集中的地方应用验证规则变得简单,现在,只要ContactPersonViewModel在程序中被用到了,则验证规则同时也会被应用到。但现在DefaultModelBinder内的DataAnnotations被支持,下面来看新版本的Add Partial View:

 
 
 
 
  1. <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> 
  2.  
  3.  
  4.   $(function() {  
  5.   $('#DateOfBirth').datepicker({ dateFormat: 'yy/mm/dd' });  
  6.   });  
  7.   $('#save').click(function () {  
  8. $.ajax({  
  9.     type: "POST",  
  10.     url: $("#AddContact").attr('action'),  
  11.     data: $("#AddContact").serialize(),  
  12.     dataType: "text/plain",  
  13.     success: function (response) {  
  14.   if (response == "Saved") {  
  15. window.location = "/";   
  16.   }else {  
  17. $("#details").html(response);  
  18.   }  
  19.     }  
  20. });  
  21.   });  
  22.  
  23.  
  24. <% using (Html.BeginForm("Add", "Contact", FormMethod.Post, new { id = "AddContact" }))  
  25.    {%> 
  26.  
  27.   
  28.  
  29. <%= Html.LabelFor(m => m.FirstName)%>  
  30.     
  31.   
  32.  
  33.   
  34.  
  35. <%= Html.LabelFor(m => m.MiddleName)%>  
  36.     
  37.   
  38.  
  39.   
  40.  
  41. <%= Html.LabelFor(m => m.LastName)%>  
  42.     
  43.   
  44.  
  45.   
  46.  
  47. <%= Html.LabelFor(m => m.DateOfBirth)%>  
  48.     
  49.   
  50.  
  51.   
  52.  
  53.     <%= Html.LabelFor(m => m.Type)%> 
  54.     
  55.  
  56.   
  57.  
  58.   
  59.  
  60.      
  61.     
  62.  
  63.   
  64.  
  65. <%= Html.TextBox(m => m.FirstName)%>   
  66. <%= Html.ValidationMessageFor(m => m.FirstName)%>
  67. <%= Html.TextBox(m => m.MiddleName)%>
    <%= Html.TextBox(m => m.LastName)%>   
  68. <%= Html.ValidationMessageFor(m => m.LastName)%>
  69. <%= Html.TextBox(m => m.DateOfBirth)%>   
  70. <%= Html.ValidationMessageFor(m => m.DateOfBirth)%>
  71. <%= Html.DropDownList("Type")%> 
  72.     
  73.  
  74. <% } %>  

可以看出,这里使用新的强类型Html Helper.对前面项目修改的两处是利用了jQuery代码。***处是添加联系人的Partial View是通过AJax提交,如果验证失败,则添加的form会再次被显示,如果验证通过,新的联系人被添加到列表中,页面会刷新继而显示更新后包含新联系人的列表。

由于下面几种原因,原来的Action方法需要被修正。首先修改action方法使其接受ContactPersonViewModel而不是ContactPerson作为参数,这是因为相关的验证规则应用于ContactPersonViewModel,如果不将参数类型改变,那model binder依然能将传入的值和ContactPerson的属性相匹配,但所有的验证规则就不复存在了。第二个改变是检查ModelState的IsValid属性是否有效,否则整个验证就变得毫无意义.

 
 
 
 
  1. [AcceptVerbs(HttpVerbs.Post)]  
  2. public ActionResult Add([Bind(Exclude = "Id, Type")]ContactPersonViewModel person)  
  3. {  
  4.  
  5.     if (ModelState.IsValid)  
  6.     {  
  7.   var p = new ContactPerson  
  8.   {  
  9. FirstName = person.FirstName,  
  10. MiddleName = person.MiddleName,  
  11. LastName = person.LastName,  
  12. Type = Request.Form["Type"].ParseEnum()  
  13.   };  
  14.   if (person.DateOfBirth != null)  
  15. p.DateOfBirth = (DateTime)person.DateOfBirth;  
  16.   ContactPersonManager.Save(p);  
  17.   return Content("Saved");  
  18.     }  
  19.     var personTypes = Enum.GetValues(typeof(PersonType))  
  20.     .Cast()  
  21.     .Select(p => new  
  22.     {  
  23.   ID = p,  
  24.   Name = p.ToString()  
  25.     });  
  26.     person.Type = new SelectList(personTypes, "ID", "Name");  
  27.     return PartialView(person);  
  28. }   
  29.  

在model绑定过程中,我去掉了id和Type属性,因为在把联系人添加到数据库以前并不会存在id属性,而去掉Type属性是因为在ViewModel中它的类型是SelectList,但在BLL层中ContactPerson对象中却是枚举类型,如果ModelState的IsValid属性为True(注:既验证通过),则ViewModel的属性会和ContactPerson对象的属性进行匹配,如果IsValid不为True,数据会回传到View中显示验证失败的相关信息。

上面代码中我们注意到了Request.Form[“Type”]这个string类型的ParseEnum扩展方法,这也是为什么我去掉Type属性,只有这样它才会被转换为适当的类型。扩展方法的原型(在我的Google Analytics 文中)如下:

 
 
 
 
  1. public static T ParseEnum(this string token)  
  2. {  
  3.     return (T)Enum.Parse(typeof(T), token);  
  4. }  
  5.  
  6. edit  

这个action方法也是如此,除了对DateOfBirth进行编辑那部分:

 
 
 
 
  1.  
  2.   <%= Html.LabelFor(m => m.DateOfBirth)%>  
  3.   <%= Html.EditorFor(m => m.DateOfBirth)%>   
  4. <%= Html.ValidationMessageFor(m => m.DateOfBirth)%>    
  5.   

这里我并没有使用TextBoxFor扩展方法,而是使用了EditorFor方法,默认情况下,DateTime类型都以hh:mm:ss这样的方式显示,但我并不喜欢这种格式,所以我创建了一个格式化显示时间日期的模板,在View/Shared目录下,我添加了一个名为EditorTemplates(这也是MVC中应有命名方式,因为MVC会自动搜索这个位置)并在此目录下添加一个名为DateTime的Partial View,这也是MVC的惯例,而DateTime.ascx的代码如下:

 
 
 
 
  1. <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> 
  2. <%= Html.TextBox("", Model.HasValue ? Model.Value.ToShortDateString() : string.Empty) %> 

虽然只有短短两行代码,但是可以让时间日期如果为空时,什么都不显示,而如果时间存在,则以ShortDate的格式显示。

总结

本篇文章研究了ASP.Net MVC 2.0中利用DataAnnotations来进行验证,现在这已经是.net framework的一部分。文中还简单的接触了新版本中的一些特性,包括强类型的HTML Helper以及模板。本篇文章的代码使用Visual Studio 2010 RC1创建的,所以代码不能在VWD和Visual Studio的环境中调试。

名称栏目:使用VisualStudio2010和MVC2.0增强验证功能
转载来于:http://www.36103.cn/qtweb/news44/29394.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联