前兩節講的都是asp.net mvc3預先設定的數據注解,但是系統自由的數據注解肯定不適合所有的場合,所以有時候我們需要自定義數據注解。
自定義數據注解有兩種,一種是直接寫在模型對象中,這樣做的好處是驗證時只需要關心一種模型對象的驗證邏輯,缺點也是顯而易見的,那就是不能重用。
還有一種是封裝在自定義的數據注解中,優點是可重用,缺點是需要應對不同類型的模型。
現在我們以封裝在自定義數據注解中的方法為例看下如何在asp.net mvc3中自定義數據注解以及使用。
一、自定義屬性級別的驗證
首先,所有的數據注解都應繼承於
System.ComponentModel.DataAnnotations命名空間中的
ValidationAttribute類。
重寫其
protected virtual ValidationResult IsValid(object value, ValidationContext validationContext);
例如:
我們需要寫一個UserName不能超過10個字母的數據注解(你可能會說這不是有的
StringLength么,好吧,僅以此為例,我真沒想到其他的需要自定義數據注解的好例子)。
(1)新建一個類
MaxLengthAttribute,代碼如下:
public class MyMaxLengthAttribute : ValidationAttribute
{
private readonly int MaxLength;
public MyMaxLengthAttribute(int maxLength)
{
MaxLength = maxLength;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string content = value.ToString();
if (content.Length > MaxLength)
{
return new ValidationResult("輸入的字符太多了!^_^");
}
return ValidationResult.Success;
//return base.IsValid(value, validationContext);
}
第二步就是像正常使用asp.net自帶的數據注解一樣使用,如:
[Required(ErrorMessageResourceType=typeof(ErrorMessage),ErrorMessageResourceName="UserRequire")]
[Display(Name = "用戶名")]
[MyMaxLengthAttribute(10)]
[Remote("CheckUserName","Account", HttpMethod="POST")]
public string UserName { get; set; }
好了,只需要這樣簡單的兩步就可以實現了。

驗證結果:
對於自定義的數據注解由於是繼承於
System.ComponentModel.DataAnnotations命名空間中的
ValidationAttribute類,所以它的一些屬性也可以使用,比如ErrorMessage,如:
[Required(ErrorMessageResourceType=typeof(ErrorMessage),ErrorMessageResourceName="UserRequire")]
[Display(Name = "用戶名")]
[MyMaxLengthAttribute(10,ErrorMessage="{0}字數太多")]
[Remote("CheckUserName","Account", HttpMethod="POST")]
public string UserName { get; set; }
需要注意的是,自定義的數據注解不支持客戶端驗證,所有的數據需要提交之后再服務端驗證,所以如果要同時實現客戶端驗證需要自己寫js驗證。
但是這樣的驗證有一個問題,就是默認的驗證信息不能實現直接顯示Display Name,所以需要如下更改:
public class MyMaxLengthAttribute : ValidationAttribute
{
private readonly int MaxLength;
public MyMaxLengthAttribute(int maxLength ):base("{0}的字符太多了!")
{
MaxLength = maxLength;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
string content = value.ToString();
if (content.Length > MaxLength)
{
//return new ValidationResult("輸入的字符太多了!^_^");
string errorMessage = FormatErrorMessage(validationContext.DisplayName);
return new ValidationResult(errorMessage);
}
return ValidationResult.Success;
//return base.IsValid(value, validationContext);
}
}
驗證結果:

二、自定義Model級別的驗證(IValidatableObject)
這個接口是為了實現Model的自驗證(self-validating)的,是asp.net mvc3 新增的驗證特性。這個特性和普通數據注解的區別是普通數據注解僅僅只能驗證Model的一個屬性,而實現了IValidatableObject接口的自驗證則在Model的級別來驗證,比如驗證Model的幾個屬性之間的關系等。
例如,我要驗證兩次輸入的密碼相同(好吧,我又把系統自帶的驗證再寫一遍)。
(1)首先,要將需要驗證的Model實現IValidatableObject接口。
public class RegisterModel : IValidatableObject
(2)在Model中實現
Validate方法:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContent) { if (Password != ConfirmPassword) { yield return new ValidationResult("兩次輸入的密碼不同!", new[] { "Password" }); } }
這個方法在提交Model時會自動驗證兩次輸入的密碼是否相同,如果不同則會提示,如下:

注意:1、自驗證只能把方法寫在需要驗證的Model中,所以這種自驗證的代碼無法重用;
2、自驗證的返回值是
IEnumerable<ValidationResult>,而不是
ValidationResult,所以返回值可以不止一個驗證錯誤。
3、Validate方法沒有傳入value參數,也就是意味着Validate方法可以直接訪問Model中的屬性值。
4、返回值使用的是yield return來構建枚舉返回值,第二個參數是指定錯誤信息綁定的屬性,因為是string數組,所以可以關聯多個屬性。
順便把練習用的源碼分享了,Model部分主要在RegisterModel,下載請點擊:
http://pan.baidu.com/share/link?shareid=143863&uk=4044128861
