您的位置:首頁>正文

ASP.NET MVC5(四):資料注解和驗證

前言

用戶輸入驗證的工作, 不僅要在用戶端流覽器中執行, 還要在服務端執行。 主要原因是用戶端驗證會對輸入資料給出即時回饋, 提高用戶體驗;伺服器端驗證, 主要是因為不能完全信任使用者提供的資料。 ASP.NET MVC框架提供了強大的驗證元件説明我們處理這些繁雜的問題。

資料驗證驗證注解的使用

驗證注解特性定義在命名空間System.ComponentModel.DataAnnotations中, 它們提供了伺服器端驗證的功能, 當在模型的屬性上使用時, 框架也支援用戶端驗證。 常用特性簡介:

Required
當屬性值為null或者空時, 將引發一個驗證錯誤, 可以理解為若添加了Required特性,
則此項為必填項。 StringLength
限定字串長度。 RegularExpression
使用規則運算式驗證輸入的字串是否符合格式要求。 Range
用來指定輸入數值來的最小值和最大值。 Compare
用來判斷兩個屬性是否擁有相同的值。 例如, 確保兩次輸入的密碼相同。 Remote
利用伺服器端的回呼函數執行用戶端的邏輯驗證。

下面, 通過一個簡單的示例來講解這些特性的使用方法。 假設現在我們開發一套圖書管理系統, 在Models資料夾中創建Book類, 用來保存書籍的基本資訊。

public class Book { public int Id { get; set; } public string Name { get; set; } public string Author { get; set; } public int PagesNumber { get; set; } public string Publisher { get; set; } public string PublicationDate { get; set; } public string Content { get; set; } public decimal Price { get; set; } public decimal PriceConfirm { get; set; } }

添加BooksController, 啟動專案, 此時, ASP.NET MVC已經利用基架範本説明我們創建好了相應的controller和View, 直接將流覽器定位到/Books/Create, 可流覽如下用來添加書籍的頁面。

在添加書籍時, 使用者希望對輸入的資料進行一些驗證, 當輸入的資料無法通過相關驗證時, 返回錯誤資訊。 此時, 驗證注解特性就派上了用場。 第一步, 引入命名空間

using System.ComponentModel.DataAnnotations; using System.Web.Mvc;

向BooksController中添加CheckContent方法(為了使用remote特性做準備)

public JsonResult CheckContent(string content) { var result = db.Books.Where(m => m.Content == content).Count == 0; return Json(result, JsonRequestBehavior.AllowGet); }

修改Book類, 分別添加驗證注解:

public int Id { get; set; } [Required] //必填 public string Name { get; set; } [StringLength(50)] //作者姓名的長度不能超過50個字元 public string Author { get; set; } [Range(100, 10000)] //頁數保證在100~10000頁之間 public int PagesNumber { get; set; } public string Publisher { get; set; } [RegularExpression(@"^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$")] //日期格式 public string PublicationDate { get; set; } [Remote("CheckContent", "Books")] //內容介紹不能重複 public string Content { get; set; } public decimal Price { get; set; } [System.ComponentModel.DataAnnotations.Compare("Price")] //兩次輸入的價格必須一致 public decimal PriceConfirm { get; set; }

重新開機專案,

在Create頁面輸入不符合驗證邏輯的資料, 效果如下:

重新輸入正確的資料, 點擊Create, 資料成功錄入後, 我們再錄入另外一本書籍, Content內容與上一次添加的內容相同, 得到錯誤資訊, 此時Remote特性調用了CheckContent方法進行驗證。

★注意, Remote特性自動發送AJAX請求訪問後臺代碼來實現驗證, 它只有用戶端驗證, 沒有服務端驗證。 也就是說, 當用戶流覽器關閉js, Remote檢查將不起作用, 因此, Remote特性存在一定的安全隱患。 同理, 如果創建Controller時沒有勾選Reference script libraries選項, Remote特性也將不起任何作用。

自訂錯誤提示

每個驗證特性都允許傳入一個帶有自訂錯誤提示消息的參數,

例如以上示例中RegularExpression特性返回的錯誤消息, 使用者可能無法理解規則運算式的含義, 此時, 我們就需要返回一些簡單易懂的錯誤消息, 向RegularExpression傳入ErrorMessage參數。

[RegularExpression(@"^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$",ErrorMessage ="請輸入有效的日期格式, 例如:2017-06-16")] //日期格式 public string PublicationDate { get; set; }

效果如下:

驗證注解的後臺原理及控制器操作

預設情況下, ASP.NET MVC框架在模型綁定時執行驗證邏輯。 模型綁定器一旦使用新值完成對模型屬性的更新, 就會利用當前的模型中繼資料獲得模型的所有驗證器。 ASP.NET MVC運行時提供了一個驗證器DataAnnotationsModelValidator來與資料注解一同工作。 這個模型驗證器會找到所有的驗證特性並執行它們包含的驗證邏輯。 模型綁定器捕獲所有失敗的驗證規則並把它們存放在模型狀態中。

控制器操作決定了在模型驗證失敗或成功時程式的執行流程。 通常情況下,驗證成功,保存使用者輸入資料,驗證失敗,重新渲染視圖,返回錯誤消息。以下是系統自動創建的Create方法,首先判斷模型狀態ModelState是否存在錯誤,若不存在,則保存書籍資訊,若存在敗,則重新渲染視圖。

[HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include = "Id,Name,Author,PagesNumber,Publisher,PublicationDate,Content,Price,PriceConfirm")] Book book) { if (ModelState.IsValid) { db.Books.Add(book); db.SaveChanges; return RedirectToAction("Index"); } return View(book); }

自訂驗證邏輯

上一節中介紹了這麼多驗證注解,我們不禁會問,用戶經常會提出很多奇葩的需求,我們能否自己定義一些驗證邏輯呢?答案是肯定的。本節,將介紹如何完成自訂邏輯驗證。

自訂注解

所有驗證注解特性最終都派生自基類ValidationAttribute,它是個抽象類別,因此,創建自訂注解特性時也必須派生自ValidationAttribute類。 假設用戶提出一個需求,由於某位作者遭到無情封殺,錄入書籍資訊時,作者一欄不能為指定的人名。

首先,添加CheckAuthorAttribute類派生自基類ValidationAttribute:

using System.ComponentModel.DataAnnotations; namespace MyFirstMvcProject.Infrastructure { public class CheckAuthorAttribute : ValidationAttribute { } }

為了實現這個驗證,需要重寫基類的IsValid方法,ValidationContext參數提供了可在IsValid方法內部使用的資訊,如模型類型、模型物件實例、用來驗證屬性的顯示名稱等。IsValid方法的第一個參數是要驗證的物件的值,另外,我們通過構造函數獲取不能通過驗證的人名。

public class CheckAuthorAttribute : ValidationAttribute { public string Author { get; set; } public CheckAuthorAttribute(string author) : base("{0} can not be this one. ") { this.Author = author; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value != null) { if (value.ToString == Author) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } } return ValidationResult.Success; } }

上述代碼有兩點需要注意:

向基類構造函數傳遞一個預設值的錯誤提示資訊。
FormatErrorMessage方法:基於出現比較錯誤的資料欄位對錯誤消息應用格式設置。

修改Book類,在Author屬性上添加CheckAuthor特性。

[StringLength(50)] //作者姓名的長度不能超過50個字元 [CheckAuthor("Thomas", ErrorMessage = "Author can not be this one.")] public string Author { get; set; }

運行程式,輸入Author,點擊Create,效果如下:

到目前為止,我們已經成功創建自訂注解特性,但是細心的用戶又發現了,新添加的驗證只有在點擊了Create後才能觸發,其他的驗證都可以給出即時回饋。正如使用者所說,目前我們只添加了服務端驗證,下面將介紹如何為CheckAuthor特性添加用戶端驗證。

修改MaxWordsAttribute類,使其繼承IClientValidatable介面,實現GetClientValidationRules方法。

public class CheckAuthorAttribute : ValidationAttribute, IClientValidatable { public string Author { get; set; } public CheckAuthorAttribute(string author) : base("{0} can not be this one. ") { this.Author = author; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value != null) { if (value.ToString == Author) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } } return ValidationResult.Success; } public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule { ValidationType = "checkauthor", ErrorMessage = FormatErrorMessage(metadata.GetDisplayName) }; rule.ValidationParameters.Add("author", Author); yield return rule; } }

說明:

IClientValidatable介面為ASP.NET MVC驗證框架提供一種用於在運行時發現驗證程式是否支援用戶端驗證的方法。GetClientValidationRules在類中實現,返回該類的用戶端驗證規則。ErrorMessage屬性用於存放錯誤提示消息。ValidationParameters集合用於存放用戶端需要的參數,本例中即為Thomas.ValidationType屬性標識了用戶端需要的一段JavaScript代碼。

在Scripts資料夾下添加JavaScript檔,命名為customvalidators.js,鍵入如下代碼:

/// /// $.validator.addMethod("checkauthor", function (value, element, author) { if (value) { if (value == author) { return false; } } return true; }); $.validator.unobtrusive.adapters.addSingleVal("checkauthor", "author");

說明:

AddSingleVal為需要從中繼資料中檢索唯一參數值的驗證規則創建適配器。第一個參數是適配器名稱,第二個參數是要從中繼資料中檢索的參數的名稱。調用validator.AddMethod方法添加新的驗證器。

最後,在Views/Books/Create.cshtml中添加對customvalidators.js的引用:

@section Scripts { @Scripts.Render("~/bundles/jqueryval") }

啟動程式,將Url定位到/Books/Create,在Author文字方塊中輸入Thomas,當焦點離開Author文字方塊後即可完成驗證。

通常情況下,驗證成功,保存使用者輸入資料,驗證失敗,重新渲染視圖,返回錯誤消息。以下是系統自動創建的Create方法,首先判斷模型狀態ModelState是否存在錯誤,若不存在,則保存書籍資訊,若存在敗,則重新渲染視圖。

[HttpPost] [ValidateAntiForgeryToken] public ActionResult Create([Bind(Include = "Id,Name,Author,PagesNumber,Publisher,PublicationDate,Content,Price,PriceConfirm")] Book book) { if (ModelState.IsValid) { db.Books.Add(book); db.SaveChanges; return RedirectToAction("Index"); } return View(book); }

自訂驗證邏輯

上一節中介紹了這麼多驗證注解,我們不禁會問,用戶經常會提出很多奇葩的需求,我們能否自己定義一些驗證邏輯呢?答案是肯定的。本節,將介紹如何完成自訂邏輯驗證。

自訂注解

所有驗證注解特性最終都派生自基類ValidationAttribute,它是個抽象類別,因此,創建自訂注解特性時也必須派生自ValidationAttribute類。 假設用戶提出一個需求,由於某位作者遭到無情封殺,錄入書籍資訊時,作者一欄不能為指定的人名。

首先,添加CheckAuthorAttribute類派生自基類ValidationAttribute:

using System.ComponentModel.DataAnnotations; namespace MyFirstMvcProject.Infrastructure { public class CheckAuthorAttribute : ValidationAttribute { } }

為了實現這個驗證,需要重寫基類的IsValid方法,ValidationContext參數提供了可在IsValid方法內部使用的資訊,如模型類型、模型物件實例、用來驗證屬性的顯示名稱等。IsValid方法的第一個參數是要驗證的物件的值,另外,我們通過構造函數獲取不能通過驗證的人名。

public class CheckAuthorAttribute : ValidationAttribute { public string Author { get; set; } public CheckAuthorAttribute(string author) : base("{0} can not be this one. ") { this.Author = author; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value != null) { if (value.ToString == Author) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } } return ValidationResult.Success; } }

上述代碼有兩點需要注意:

向基類構造函數傳遞一個預設值的錯誤提示資訊。
FormatErrorMessage方法:基於出現比較錯誤的資料欄位對錯誤消息應用格式設置。

修改Book類,在Author屬性上添加CheckAuthor特性。

[StringLength(50)] //作者姓名的長度不能超過50個字元 [CheckAuthor("Thomas", ErrorMessage = "Author can not be this one.")] public string Author { get; set; }

運行程式,輸入Author,點擊Create,效果如下:

到目前為止,我們已經成功創建自訂注解特性,但是細心的用戶又發現了,新添加的驗證只有在點擊了Create後才能觸發,其他的驗證都可以給出即時回饋。正如使用者所說,目前我們只添加了服務端驗證,下面將介紹如何為CheckAuthor特性添加用戶端驗證。

修改MaxWordsAttribute類,使其繼承IClientValidatable介面,實現GetClientValidationRules方法。

public class CheckAuthorAttribute : ValidationAttribute, IClientValidatable { public string Author { get; set; } public CheckAuthorAttribute(string author) : base("{0} can not be this one. ") { this.Author = author; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { if (value != null) { if (value.ToString == Author) { return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } } return ValidationResult.Success; } public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule { ValidationType = "checkauthor", ErrorMessage = FormatErrorMessage(metadata.GetDisplayName) }; rule.ValidationParameters.Add("author", Author); yield return rule; } }

說明:

IClientValidatable介面為ASP.NET MVC驗證框架提供一種用於在運行時發現驗證程式是否支援用戶端驗證的方法。GetClientValidationRules在類中實現,返回該類的用戶端驗證規則。ErrorMessage屬性用於存放錯誤提示消息。ValidationParameters集合用於存放用戶端需要的參數,本例中即為Thomas.ValidationType屬性標識了用戶端需要的一段JavaScript代碼。

在Scripts資料夾下添加JavaScript檔,命名為customvalidators.js,鍵入如下代碼:

/// /// $.validator.addMethod("checkauthor", function (value, element, author) { if (value) { if (value == author) { return false; } } return true; }); $.validator.unobtrusive.adapters.addSingleVal("checkauthor", "author");

說明:

AddSingleVal為需要從中繼資料中檢索唯一參數值的驗證規則創建適配器。第一個參數是適配器名稱,第二個參數是要從中繼資料中檢索的參數的名稱。調用validator.AddMethod方法添加新的驗證器。

最後,在Views/Books/Create.cshtml中添加對customvalidators.js的引用:

@section Scripts { @Scripts.Render("~/bundles/jqueryval") }

啟動程式,將Url定位到/Books/Create,在Author文字方塊中輸入Thomas,當焦點離開Author文字方塊後即可完成驗證。

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示