文章出處

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


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()