一般網頁驗證可分成 Client 與 Server 端上進行,在以往若要同時撰寫二端的驗證程式都必須花費不少功夫, 現在 MVC 3.0 整合了多項技術,利用 Model Metadata 的設定,讓程式可以自動產生驗證功能的程式碼。
MVC Validation
Server-side Validation
要驗證資料的有效性,我們可以在 server-side 撰寫驗證程式碼。其步驟如下:
1.在 View Page 中加入 ValidationExtensions :
- ValidationMessage :輸出驗證錯誤的訊息
- ValidationSummary :輸出驗證錯誤的訊息清單
2.在 Server 端,透過 ModelState 來自訂錯的內容
@model MVC4_EX1.Models.GuestBook Title: @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) Content: @Html.EditorFor(model => model.Content) @Html.ValidationMessageFor(model => model.Content)
[HttpPost] public ActionResult Create(GuestBook guestbook) { if (string.IsNullOrEmpty(guestbook.Title)) this.ModelState.AddModelError("Title", "Title不可以為空白"); if (string.IsNullOrEmpty(guestbook.Content)) this.ModelState.AddModelError("Content", "Content不可以為空白"); if (ModelState.IsValid) { db.GuestBooks.AddObject(guestbook); db.SaveChanges(); return RedirectToAction("Index"); } return View(guestbook); }
在上面程式碼中,我們使用 ModelState.AddModelError 來加入自訂的錯誤訊息, 它會顯示在 View 的 Html.ValidationMessage 或 Html.ValidationSummary 的位置,若沒有錯誤訊息則不會顯示。 隨後可利用 ModelState.IsValid 來確認 Model 的有效性,以決定是否要取用 Model 的資料或是提示使用者錯誤訊息。
程式的執行結果是:
Client-side Validation
ASP.NET MVC 本身並未內建自動化的 client validation,它是直接使用 Dynamic Data 所提供的 Model Validation 功能。
Model Validation 指的是使用 metadata 來設定欄位資訊和驗證功能。 要套用這個功能,你只要在 Model 層中建立該物件類別的 metadata ,並直接加上驗證指令, 它就會配合用戶端的 Client-side library 做協同處理,達到 client-validation 的功能。
這些 MetadataType 屬性,也就是所有的驗證規則,都包含在 System.ComponentModel.DataAnnotations 命名空間之中。 要使用 client-validation 的步驟如下:
- 先建一個 metadata 類別 (using DataAnnotations )
- 再建立一個該資料模型的 partial 類別,並透過 MetadataType 屬性指定其 metadata 類別
Create Metadta Class
public class GuestBookMetadata { [Required] public string Title { get; set; } [Required] public string Content { get; set; } } [MetadataType(typeof(GuestBookMetadata))] public partial class GuestBook { }
Controller
在建立 metadata 類別之後,controller 會依據 metadata 中的設定去處理商務規則。 接著使用 ModelState.IsValid 方法檢查是否所有的驗證規則都有過關, 如果驗證沒過關,錯誤訊息將被 render 在 ResultView 中, 如果驗證過關,則使用者將被帶到索引頁。
[HttpPost] public ActionResult Create(GuestBook guestbook) { if (ModelState.IsValid) { db.GuestBooks.AddObject(guestbook); db.SaveChanges(); return RedirectToAction("Index"); } return View(guestbook); }
View
底下是一個 Create 型態的強型別 view 。 在這個 View 中,使用 helper 類別中的 ValidationMessageFor 和 ValidationSummary 來產生驗證項目。 同時必須要確認在 ViewPage 中是否有載入相關的 js 檔。
若為 MVC2 則為 MicrosoftAjax.js 和 MicrosoftMvcValidation.js 。
若為 MVC3 則為 jquery.validate.min.js 和 jquery.validate.unobtrusive.min.js 。
若為 MVC4 則為 jqueryval.js 。
@model MVC4_EX1.Models.GuestBook @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>GuestBook</legend> <div class="editor-label"> @Html.LabelFor(model => model.Title) </div> <div class="editor-field"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> <div class="editor-label"> @Html.LabelFor(model => model.Content) </div> <div class="editor-field"> @Html.EditorFor(model => model.Content) @Html.ValidationMessageFor(model => model.Content) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
自訂錯誤訊息
當使用 Model Validation 規則來設定客戶端的驗證,它會使用預設的訊息內容,如下圖:
如果覺得訊息內容不夠友善,可以透過 ErrorMessage 參數來自行指定訊息內容。
public class GuestBookMetadata { [Required(ErrorMessage = "{0}是必要欄位")] public string Title { get; set; } [Required(ErrorMessage = "{0}是必要欄位")] [StringLength( 100, MinimumLength=10, ErrorMessage = "{0}至少要{2}個字,不超過{1}個字")] public string Content { get; set; } }
自訂錯誤訊息的 Format 項目
錯誤訊息不僅可以自訂,還可以使用 String Format 方式來指定訊息的格式。下表為各個驗證規則可設定的格式:
類別 | Format 項目說明 |
---|---|
[Compare] | {0}:欄位名稱 {1}:比對的欄位名稱 |
[CreditCard] | {0}:欄位名稱 |
[CustomValidation] | {0}:欄位名稱 |
[EmailAddress] | {0}:欄位名稱 |
[MaxLength] | {0}:欄位名稱 {1}:設定的長度 |
[MinLength] | {0}:欄位名稱 {1}:設定的長度 |
[Phone] | {0}:欄位名稱 |
[Range] | {0}:欄位名稱 {1}:最大值 {1}:最小值 |
[RegularExpression] | {0}:欄位名稱 {1}:規則運算式 |
[Remote] | {0}:欄位名稱 |
[Required] | {0}:欄位名稱 |
[StringLength] | {0}:欄位名稱 {1}:最大值 {1}:最小值 |
[Url] | {0}:欄位名稱 |
使用資源檔
上面例子,我們透過 ErrorMessage 參數來指定錯誤訊息的內容,其實這個設定,也可以直接設定在資源檔中,而且,針對不同語系,設定不同的格式內容。 要使用資源檔,必須透過 ErrorMessageResourceType 與 ErrorMessageResourceName 參數來指定資源檔名稱。
public class GuestBookMetadata { [Required(ErrorMessageResourceType = typeof(Resource1), ErrorMessageResourceName = "RequiredField")] public string Title { get; set; } [Required] public string Content { get; set; } }
資源檔內容
執行結果
使用遠端驗證(Remote)
在驗證規則中,有一個稱為 Remote 的類別,當驗證邏輯無法在用戶端完成,必須將資料送回遠端伺服器以進行驗證就可以使用這個驗證規則。 它會將表單上的欄位資料,透過 Ajax 方式,叫用遠端的 API 以進行驗證。 例如,在註冊系統中,就常會使用這個機制,用以驗證所註冊的帳號是否已經存在資料庫中。
1. 在 Model 中設定 Remote 驗證規則
使用 Remote 驗證,第一步仍然是在 model 的 property 上,套用 Remote 驗證規則。 RemoteAttribute 中的第一個參數是 action 方法,第二個參數是 controller 。
public class GuestBookMetadata { [Required(ErrorMessage = "{0}是必要欄位")] [Remote("IsTitleAvailable", "GuestBook")] public string Title { get; set; } [Required(ErrorMessage = "{0}是必要欄位")] [StringLength( 100, MinimumLength=10, ErrorMessage = "{0}至少要{2}個字,不超過{1}個字")] public string Content { get; set; } } [MetadataType(typeof(GuestBookMetadata))] public partial class GuestBook { }
2. 在 Controller 中,撰寫驗證邏輯的 Action 方法
使用 Remote 驗證,第二步就是在 controller 中撰寫驗證的 action 方法。
public class GuestBookController : Controller { public ActionResult IsTitleAvailable(string title) { GuestBook guestbook = db.GuestBooks.FirstOrDefault(c => c.Title == title); if (guestbook == null) return Json(true, JsonRequestBehavior.AllowGet); else return Json("This Title is already exist", JsonRequestBehavior.AllowGet); } }
PS. Json 方法回傳內容中的第一個參數,若為字串型別,前端的 Unobtrusive JS 會當做錯誤訊息回應。
jQuery.validation
MVC 的 Client 端驗證,整合在 HtmlHelper 中,HtmlHelper 會根據 Metadata 資訊,輸出相關的 HTML 以及驗證程式碼。 從 MVC 3.0 開始,前端驗證都改用熱門的驗證工具: jQuery Validation 與 Unobtrusive JavaAcript 模式。 在 4.0 時已經設定在 Bundle 中,可以使用 @Script.Render("~/bundles/jqueryval") 載入相關的 .js 檔案。
@model MvcApplication1.Models.Customers @Html.LabelFor(model => model.ContactName) @Html.EditorFor(model => model.ContactName) @Html.ValidationMessageFor(model => model.ContactName) @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
Unobtrusive Javascript 是一種將Javascript從HTML結構抽離的設計概念(延伸閱讀: kewang, ericsk),避免在HTML標籤中夾雜onchange、onclick Attribute掛載Javascript事件,讓HTML歸HTML、Javascript歸Javascript,功能權責清楚區分,HTML也變得清爽容易閱讀。例如:
<input type="text" onclick="window.open('url')" />
改用 Unobtrusive Javascript 模式可以增加可讀性:
<input type="text" data-openwindow="url" />
詳細內容請參考黑暗大的 Blog http://blog.darkthread.net/post-2011-07-27-unobtrusive-jquery-validation.aspx
Store Generated Pattern
Entity Framework 有個 StoreGeneratedPattern 屬性, 可以設定在 SSDL 所定義的資料庫結構中的欄位, 當 insert 或 update 發生時,應該採用何種方式更新欄位值。可使用的設定值如下:
- None:預設值,表示不是由資料庫決定,所以會由程式端取得資料。
- Identity:該欄位由在 insert 時由資料庫決定,update 時不更新。
- Computed:該欄位在 insert 或 update 時都由資料庫決定。
下圖是設定 StoreGeneratedPattern 屬性的位置。 在下圖例子中,當新增一筆 GuestBook 資枓時,因為該 Model 中的 PostTime 欄位的 StoreGeneratedPattern 屬性已設定為 Identity ,所以當資料 Insert 時,該欄位就會自動依據資料庫的預設值屬性去產生。
沒有留言:
張貼留言