2014-04-09 10:18 蔣金楠 博客園 我要評論(0) 字號:T | Thtml
ASP.NET MVC採用Model綁定爲目標Action生成了相應的參數列表,可是在真正執行目標Action方法以前,還須要對綁定的參數實施驗證以確保其有效性,咱們將針對參數的驗證成爲Model綁定。總地來講,咱們能夠採用4種不一樣的編程模式來進行鍼對綁定參數的驗證。web
AD:WOT2014:用戶標籤系統與用戶數據化運營培訓專場 編程
ASP.NET MVC採用Model綁定爲目標Action生成了相應的參數列表,可是在真正執行目標Action方法以前,還須要對綁定的參數實施驗證以確保其有效性,咱們將針對參數的驗證成爲Model綁定。總地來講,咱們能夠採用4種不一樣的編程模式來進行鍼對綁定參數的驗證。mvc
1、手工驗證綁定的參數框架
在定義具體Action方法的時候,對已經成功綁定的參數實施手工驗證無疑是一種最爲直接的編程方式,接下來咱們經過一個簡單的實例來演示如何將參數驗證邏輯實如今對應的Action方法中,並在沒有經過驗證的狀況下將錯誤信息響應給客戶端。咱們在一個ASP.NET MVC應用中定義了以下一個Person類做爲被驗證的數據類型,它的Name、Gender和Age三個屬性分別表示一我的的姓名、性別和年齡。ide
public class Person 函數
{ ui
[DisplayName("姓名")] this
public string Name { get; set; } spa
[DisplayName("性別")]
public string Gender { get; set; }
[DisplayName("年齡")]
public int? Age { get; set; }
}
接下來咱們定義了以下一個HomeController。在針對GET請求的Action方法Index中,咱們建立了一個Person對象並將其做爲Model呈如今對應的View中。另外一個支持POST請求的Index方法具備一個Person類型的參數,咱們在該Action方法中先調用Validate方法對這個輸入參數實施驗證。若是驗證成功(ModeState.IsValid屬性返回True),咱們返回一個內容爲「輸入數據經過驗證」的ContentResult,不然將此參數做爲Model呈如今對應的View中。
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View(new Person());
}
[HttpPost]
public ActionResult Index(Person person)
{
Validate(person);
if (!ModelState.IsValid)
{
return View(person);
}
else
{
return Content("輸入數據經過驗證");
}
}
private void Validate(Person person)
{
if (string.IsNullOrEmpty(person.Name))
{
ModelState.AddModelError("Name", "'Name'是必需字段");
}
if (string.IsNullOrEmpty(person.Gender))
{
ModelState.AddModelError("Gender", "'Gender'是必需字段");
}
else if (!new string[] { "M", "F" }.Any(
g => string.Compare(person.Gender, g, true) == 0))
{
ModelState.AddModelError("Gender",
"有效'Gender'必須是'M','F'之一");
}
if (null == person.Age)
{
ModelState.AddModelError("Age", "'Age'是必需字段");
}
else if (person.Age > 25 || person.Age < 18)
{
ModelState.AddModelError("Age", "有效'Age'必須在18到25週歲之間");
}
}
}
如上面的代碼片段所示,咱們在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對象以編輯模式呈如今表單之中。
@model Person
<html>
<head>
<title>編輯人員信息</title>
</head>
<body>
@using (Html.BeginForm())
{
@Html.EditorForModel()
<input type="submit" value="保存"/>
}
</body>
</html>
直接運行該程序後,一個用於編輯人員基本信息的頁面會被呈現出來,若是咱們在輸入不合法的數據並提交後,相應的驗證信息會以圖1所示的形式呈現出來。
2、使用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。
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class DomainAttribute : ValidationAttribute
{
public IEnumerable<string> Values { get; private set; }
public DomainAttribute(string value)
{
this.Values = new string[] { value };
}
public DomainAttribute(params string[] values)
{
this.Values = values;
}
public override bool IsValid(object value)
{
if (null == value)
{
return true;
}
return this.Values.Any(item => value.ToString() == item);
}
public override string FormatErrorMessage(string name)
{
string[] values = this.Values.Select(value => string.Format("'{0}'", value)).ToArray();
return string.Format(base.ErrorMessageString, name,string.Join(",", values));
}
}
因爲ASP.NET MVC在進行參數綁定的時候會自動提取應用在目標參數類型或者數據成員上的ValidationAttribute特性,並利用它們對提供的數據實施驗證,因此咱們再也不須要像上面演示的實例同樣自行在Action方法中實施驗證,而只須要在定義參數類型Person的時候應用相應的ValidationAttribute特性將採用的驗證規則與對應的數據成員相關聯。
以下所示的是屬性成員上應用了相關ValidationAttribute特性的Person類型的定義。咱們在三個屬性上均應用了RequiredAttribute特性將它們定義成必需的數據成員,Gender和Age屬性上則分別應用了DomainAttribute和RangeAttribute特性對有效屬性值的範圍做了相應限制。
public class Person
{
[DisplayName("姓名")]
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources))]
public string Name { get; set; }
[DisplayName("性別")]
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources))]
[Domain("M", "F", "m", "f", ErrorMessageResourceName = "Domain", ErrorMessageResourceType = typeof(Resources))]
public string Gender { get; set; }
[DisplayName("年齡")]
[Required(ErrorMessageResourceName = "Required", ErrorMessageResourceType = typeof(Resources))]
[Range(18, 25, ErrorMessageResourceName = "Range", ErrorMessageResourceType = typeof(Resources))]
public int? Age { get; set; }
}
三個ValidationAttribute特性採用的錯誤消息均定義在項目默認的資源文件中(咱們能夠採用這樣的步驟建立這個資源文件:右鍵選擇Solution Exploror中的項目,並在上下文菜單中選擇「屬性」選項打開「項目屬性」對象框。最後在對話框中選擇「資源」Tab頁面,經過點擊頁面中的連接建立一個資源文件),具體定義如圖2所示。
因爲ASP.NET MVC會自動提取應用在綁定參數類型上的ValidationAttribute特性對綁定的參數實施自動化驗證,因此咱們根本不須要在具體的Action方法中來對參數做手工驗證。以下面的代碼片段所示,咱們在Action方法Index中再也不顯式調用Validate方法,可是運行該程序並在輸入不合法數據的狀況下提交表單後依然會獲得如圖1所示的輸出結果。
public class HomeController : Controller
{
//其餘成員
[HttpPost]
public ActionResult Index(Person person)
{
if (!ModelState.IsValid)
{
return View(person);
}
else
{
return Content("輸入數據經過驗證");
}
}
}
3、讓數據類型實現IValidatableObject接口
除了將驗證規則經過ValidationAttribute特性直接定義在數據類型上並讓ASP.NET MVC在進行參數綁定過程當中據此來驗證參數以外,咱們還能夠將驗證操做直接定義在數據類型中。既然咱們將驗證操做直接實如今了數據類型上,意味着對應的數據對象具備「自我驗證」的能力,咱們姑且將這些數據類型稱爲「自我驗證類型」。這些自我驗證類型是實現了具備以下定義的接口IValidatableObject,該接口定義在「System.ComponentModel.DataAnnotations」命名空間下。
public interface IValidatableObject
{
IEnumerable<ValidationResult> Validate( ValidationContext validationContext);
}
如上面的代碼片段所示,IValidatableObject接口具備惟一的方法Validate,針對自身的驗證就實如今該方法中。對於上面演示實例中定義的數據類型Person,咱們能夠按照以下的形式將它定義成自我驗證類型。
public class Person: IValidatableObject
{
[DisplayName("姓名")]
public string Name { get; set; }
[DisplayName("性別")]
public string Gender { get; set; }
[DisplayName("年齡")]
public int? Age { get; set; }
public IEnumerable<ValidationResult> Validate( ValidationContext validationContext)
{
Person person = validationContext.ObjectInstance as Person;
if (null == person)
{
yield break;
}
if(string.IsNullOrEmpty(person.Name))
{
yield return new ValidationResult("'Name'是必需字段", new string[]{"Name"});
}
if (string.IsNullOrEmpty(person.Gender))
{
yield return new ValidationResult("'Gender'是必需字段", new string[] { "Gender" });
}
else if (!new string[]{"M","F"}.Any( g=>string.Compare(person.Gender,g, true) == 0))
{
yield return new ValidationResult("有效'Gender'必須是'M','F'之一", new string[] { "Gender" });
}
if (null == person.Age)
{
yield return new ValidationResult("'Age'是必需字段", new string[] { "Age" });
}
else if (person.Age > 25 || person.Age < 18)
{
yield return new ValidationResult("'Age'必須在18到25週歲之間", new string[] { "Age" });
}
}
}
如上面的代碼片段所示,咱們讓Person類型實現了IValidatableObject接口。在實現的Validate方法中,咱們從驗證上下文中獲取被驗證的Person對象,並對其屬性成員進行逐個驗證。若是數據成員沒有經過驗證,咱們經過一個ValidationResult對象封裝錯誤消息和數據成員名稱(屬性名),該方法最終返回的是一個元素類型爲ValidationResult的集合。在不對其餘代碼做任何改動的狀況下,咱們直接運行該程序並在輸入不合法數據的狀況下提交表單後依然會獲得如圖1所示的輸出結果。
4、讓數據類型實現IDataErrorInfo接口
上面咱們讓數據類型實現IValidatableObject接口並將具體的驗證邏輯定義在實現的Validate方法中,這樣的類型可以被ASP.NET MVC所識別,後者會自動調用該方法對綁定的數據對象實施驗證。若是咱們讓數據類型實現IDataErrorInfo接口也能實現相似的自動化驗證效果。
IDataErrorInfo接口定義在「System.ComponentModel」命名空間下,它提供了一種標準的錯誤信息定製方式。以下面的代碼片斷所示,IDataErrorInfo具備兩個成員,只讀屬性Error用於獲取基於自身的錯誤消息,而只讀索引用於返回指定數據成員的錯誤消息。
public interface IDataErrorInfo
{
string Error { get; }
string this[string columnName] { get; }
}
一樣是針對上面演示的實例,如今咱們對須要被驗證的數據類型Person進行了從新定義。以下面的代碼片段所示,咱們讓Person實現了IDataErrorInfo接口。在實現的索引中,咱們將索引參數columnName視爲屬性名稱,根據它按照上面的規則對相應的屬性成員實施驗證,並在驗證失敗的狀況下返回相應的錯誤消息。在不對其餘代碼做任何改動的狀況下,咱們直接運行該程序並在輸入不合法數據的狀況下提交表單後依然會獲得如圖1所示的輸出結果。
public class Person : IDataErrorInfo
{
[DisplayName("姓名")]
public string Name { get; set; }
[DisplayName("性別")]
public string Gender { get; set; }
[DisplayName("年齡")]
public int? Age { get; set; }
[ScaffoldColumn(false)]
public string Error { get; private set; }
public string this[string columnName]
{
get
{
switch (columnName)
{
case "Name":
{
if(string.IsNullOrEmpty(this.Name))
{
return "'姓名'是必需字段";
}
return null;
}
case "Gender":
{
if (string.IsNullOrEmpty(this.Gender))
{
return "'性別'是必需字段";
}
else if (!new string[] { "M", "F" }.Any(
g => string.Compare(this.Gender, g, true) == 0))
{
return "'性別'必須是'M','F'之一";
}
return null;
}
case "Age":
{
if (null == this.Age)
{
return "'年齡'是必需字段";
}
else if (this.Age > 25 || this.Age < 18)
{
return "'年齡'必須在18到25週歲之間";
}
return null;
}
default: return null;
}
}
}
}
原文連接:http://www.cnblogs.com/artech/p/asp-net-mvc-validation-programming.html