只要一直走,慢點又何妨。
在使用MVC模式進行開發時,數據注解是經常使用的(模型之上操作),下面是我看書整理的一些常見的用法。
什么是驗證,數據注解
驗證
從全局來看,發現邏輯僅是整個驗證的很小的一部分。驗證首先需要管理用戶友好(本地化)的與驗證邏輯相關的錯誤提示消息;當驗證失敗時,在把這些錯誤提示消息呈現給用戶界面上,當然還要向用戶提供從驗證失敗中恢復的機制。
數據注解
注解是一種通用機制,可以用來向框架注入元數據,同時,框架不只驅動元數據的驗證,還可以在生成顯示和編輯模型的HTML標記時使用元數據。通俗的說就是模型上面的特定標識符(具有一定意義和作用)。
驗證注解的使用
數據注解定義在一般在命名空間”System.ComponentModel.DataAnnotations”提供了服務器端驗證的功能,在模型屬性上使用時,框架也支持客戶端驗證。注解后面都是可以添加錯誤提示語的,ErrorMessage是每個驗證特性中用來設置錯誤提示消息的參數,比如:
[Required(ErrorMessage = "不能為空")]
public int Age { get; set; }
- Required
強調屬性是必須的,不可為空。當屬性中有一個是null或空時,會引發一個驗證錯誤。
[Required]
public int Age { get; set; }
- StringLength
要求必須輸入名字的長度。參數可以限制最小的。如下:
[StringLength(160,MinimumLength = 3)]
public string Name { get; set; }
- RegularExpression
正則表達式驗證,比如郵箱等需要驗證正則的地方。很是方便,這樣就減少了服務端的驗證。
[RegularExpression(@"^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+",ErrorMessage = "郵箱輸入有誤,重新輸入。")]
public string Email { get; set; }
- Range
用來指定數值類型值得最小值和最大值。主要為int類型服務。其余的也可以,需要使用構造函數的重載版本。Type參數來做。
[Range(20,30,ErrorMessage = "年齡不符合要求")]
public int Age { get; set; }
[Range(typeof(decimal),"0.00","59.99")]
public decimal Price { get; set; }
- Compare
確定兩個模型屬性擁有一樣的值。密碼的驗證(輸入兩次,看二者是否一樣。),參數為前面模型的值。
[Required(ErrorMessage = "密碼不能為空")]
public string Password { get; set; }
[Compare("Password")]
public string PasswordPalt { get; set; }
- Remote
此特性利用服務器端的回調函數執行客戶端的驗證邏輯。通俗的說就是這個特性可以直接找到某個控制器的action並且執行其中的方法。
/// <summary>
/// 驗證模型中輸入的姓名是否和數據庫中重復
/// </summary>
/// <returns></returns>
public JsonResult CheckUserName(string username)
{
//數據庫中的相關驗證
return Json(DateTime.Now.ToString(),JsonRequestBehavior.AllowGet);
}
[Remote("CheckUserName", "Admin")]
public string UserName { get; set; }
上面控制器操作會利用與UserName屬性同名的參數進行驗證,同時返回一個javascript object Notaion(json)對象中的布爾類型值(0/1)
- 自定義回復消息占位符
使用{0}占位符,來顯示用戶的輸入,並且形成友好提示。
[Range(20,30,ErrorMessage = "年齡{0}不符合要求")]
public int Age { get; set; }
服務端的一些處理(驗證與綁定)
ASP.NET MVC的驗證特性是由模型綁定器,模型元數據,模型驗證器和模型狀態組成。
驗證和模型綁定
- 操作方法中添加參數
這里有一個隱式地執行模型綁定,一般我們都需要這樣寫,這樣也安全,不會說暴露出來參數。
- 利用UpdateModel或TryUpdateModel方法顯式執行綁定
這個實際項目中使用的很少,一般都是通過隱式進行轉換的。
[HttpPost,ActionName("Create")]
public ActionResult CreatePost(Student model)
{
var model2 = new Student();
UpdateModel(model2);
if (TryUpdateModel(model2))
{
}
return View(model);
}
可以看到參數中的為隱式轉換,里面的model2為顯式轉換。if中的返回的是bool類型。模型綁定器一旦使用新值完成對模型屬性的更新,就會利用當前的 模型元數據獲得模型的所有驗證器。MVC運行時提供了一個驗證器(DataAnnotationsModelValidator)來與數據注解一同工作,這個模型驗證器會找到所有的驗證特性並執行它們包含的驗證邏輯,模型綁定器捕獲所有失敗的驗證規則並把它們放入模型狀態中。
編程的一個重要原則是不能相信用戶的輸入
驗證與模型狀態
模型綁定的副產品是模型狀態,也就是我們服務端驗證的ModelState,此狀態中不僅包含用戶的輸入,也含有每個相關屬性的所有錯誤(與模型狀態本身有關的錯誤),有錯誤,ModelState.IsValid就返回false。從而我們就可以進行驗證。
public ActionResult CreatePost(Student model)
{
var s=ModelState.IsValidField("UserName");
var ss=ModelState["UserName"].Errors.Count;
var userName = ModelState["UserName"].Errors[0].ErrorMessage; //獲取錯誤消息
if (ModelState.IsValid) //返回bool類型
{
}
return View(model);
}
顯示和編輯注解
- Display
顯示模型屬性設置友好的“顯示名稱”
[Display(Name = "姓名")]
[StringLength(160,MinimumLength = 3)]
public string Name { get; set; }
- ScaffoldColumn
可以隱藏HTML的輔助方法
[ScaffoldColumn(false)]
public string Address { get; set; }
- DisplayFormat
處理屬性各種格式化選項,當屬性包含空值,可以提供可選的顯示文本。也可以為包含標記的屬性關閉HTML編碼。還可以運行時指定一個應用於屬性值的格式化字符串。
[DisplayFormat(ApplyFormatInEditMode = true,DataFormatString = "{0:c}")]
public decimal Total { get; set; }
- ReadOnly
可以確保默認的模型綁定器不使用請求中的新值來更新屬性。
- DataType
運行時提供關於屬性的特定用途信息。String類型的屬性可應用於很多場合--可以保存e-mail地址,URL或密碼。
[Required(ErrorMessage = "密碼不能為空")]
[DataType(DataType.Password)]
public string Password { get; set; }
- UIHint
給運行時提供一個模版名稱,以備調用模版輔助方法渲染輸出時使用。
自定義驗證邏輯
- 將驗證邏輯封裝在自定義的數據注解中。
- 將驗證邏輯封裝在模型對象中。
把驗證邏輯封裝在自定義的數據注解中可以輕松地實現在多個模型中重用邏輯。需要在特性內部編寫代碼以應對不同類型的模型中。
自定義注解
所有的驗證注解特性最終都派生自基類ValidationAttribute,它是個抽象類,在System.ComponentMode.DataAnnotation中定義。同樣自定義的驗證邏輯必須派生自ValidationAttribute的類。且重寫IsValid方法(方法里面實現我們相應的邏輯)。
需求:限制用戶輸入地址中單詞數量,設定一個最大值。
/// <summary>
/// 自定義模型驗證
/// 輸入數字的單詞最大數量
/// </summary>
public class MaxWordsAttribute:ValidationAttribute
{
private readonly int _maxWord;
public MaxWordsAttribute(int maxWord)
{
_maxWord = maxWord;
}
protected override ValidationResult IsValid(object value,ValidationContext validationContext)
{
if (value!=null)
{
//將輸入轉換為string類型
var valueAsString = value.ToString();
//使用split(' ')空格來分隔輸入值,統計生成字符串的數量。對數目比較驗證。
if (valueAsString.Split(' ').Length>_maxWord)
{
return new ValidationResult("單詞超過長度"); //string類型
}
}
return ValidationResult.Success; //bool類型
}
}
第一個參數要驗證對象中的值。后面進行邏輯的判斷。這樣做這里的錯誤提示不能顯示到前台。我們需要修改下,使用ValidationAttrubute的ErrorMessage屬性來自定義提示錯誤消息。
修改之后
public class MaxWordsAttribute:ValidationAttribute
{
private readonly int _maxWord;
public MaxWordsAttribute(int maxWord)
:base("{0} has too many words")
{
_maxWord = maxWord;
}
protected override ValidationResult IsValid(object value,ValidationContext validationContext)
{
if (value!=null)
{
//將輸入轉換為string類型
var valueAsString = value.ToString();
//使用split(' ')空格來分隔輸入值,統計生成字符串的數量。對數目比較驗證。
if (valueAsString.Split(' ').Length>_maxWord)
{
var errorMessage = FormatErrorMessage(validationContext.DisplayName);
return new ValidationResult(errorMessage);
}
}
return ValidationResult.Success; //bool類型
}
}
[MaxWords(5)]
public string Address { get; set; }
這樣效果就會將我們基類中的錯誤信息顯示出來。
我們可以模型基礎上添加自定義錯誤顯示。
[MaxWords(5,ErrorMessage = "你輸入的單詞數超界限,請重新輸入。")]
public string Address { get; set; }
這里需要注意這里的執行順序,它是先執行模型上面的驗證,接着在到控制器中的action中去的。利用ModelState.IsValid來進行驗證。
自驗證模型(IValidatableObject)
自驗證模型是指一個知道如何驗證自身的模型對象,可以讓類實現IVaalidatableObject接口來實現對自身的驗證。
public class Information:IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (UserName!=null&&UserName.Split(' ').Length>5)
{
yield return new ValidationResult("單詞超界限了");
}
}
[Display(Name = "用戶名")]
public string UserName { get; set; }
}
其實書上面是在錯誤返回值中返回的是string類型的數組,如下
yield return new ValidationResult("單詞超界限了",new []{"UserName"});
可以我不知道從那里取出來這個錯誤消息。只能單獨的顯示出來。其實把錯誤消息放在數組中可以進行多模型的驗證,從而統一將錯誤顯示出來。
自己的感覺要是需要模型驗證,最好還是進行第一種方法,最起碼代碼看起來干凈,第二種給人的感覺是很亂,但是第二種適合比較模型多的場合。
我就是我,顏色不一樣的煙火。





