ASP.NET MVC3 如何使用內建驗證功能達到前端與後端的同時驗證
- 2011-07-06
- 34340
- 0
- ASP.NET MVC3 驗證介紹實作與擴充
撰寫網頁程式的時候經常的需要對於表單資料實行驗證的功能,在 ASP.NET MVC 2 的時代也有提供所謂的內建驗證,但因為前端是使用了 MicrosoftMvcValidation 來實作,因此很讓人不想學...而去改用其他的前端驗證,如 jQuery.Validate等好用的前端驗證,但驗證只做前端等於找死,因此又要去實作後端的部份 Code,前後改一下再加上自訂的驗證後等於自己寫了一套驗證模組,十分的辛苦,而且也不是普通使用者可以寫出來的(需要了解一些可愛的反射與屬性),但這痛苦的經驗不需要在 ASP.NET MVC 3 再來一次,因為官方提供了兩個介面(IClientValidatable、IValidatableObject)讓每位開發人員可以輕鬆簡單的擴充出自己需要的驗證規則,並且也很容易的寫成前端後端都支援的驗證。
本篇主要介紹 IClientValidatable 的使用,IClientValidatable 這個介面可以讓開發人員簡單的實現前端與後端的驗證,原生提供了 Range、 RegularExpression、Required、StringLength、Compare、Remote 這幾個實務上經常使用的驗證規則,而這次 ASP.NET MVC 3 已經改使用 jQuery.Validate 來做前端的驗證引擎,並且利用所謂的 unobtrusive 設計模式來達到整合與抽離,讓 HTML 依然漂亮,如此大的改變就能了解到 ASP.NET MVC 3 的確是彌補了上一版的不足,以下就來介紹如何使用內建的這幾項驗證規則。
先建立一個 ASP.NET MVC 3 原生的樣板,執行後前往註冊會員的頁面(預設在 /Account/Register )
什麼都不填的情況直接按下「Register」
有驗證耶
刻意關掉瀏覽器的 Javascript 讓前端驗證失效再按「Register」
神奇了,為什麼連後端驗證也有
這樣版非常好,因為它已經自訂出一個 AccountModels 並且加上了驗證,開啟以後拉到最後方找到 RegisterModel 這個 Class
public class RegisterModel { [Required] [Display(Name = "User name")] public string UserName { get; set; } [Required] [DataType(DataType.EmailAddress)] [Display(Name = "Email address")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirm password")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] public string ConfirmPassword { get; set; } }
有底色的就是關於驗證的 Attribute,因本篇主要是說明驗證因此與驗證無關的 Attribute 就不介紹了
就是因為有這些設定,因此註冊頁面才能支援前後端的驗證。
上面看到的效果就是預設的 Required 驗證規則,很簡單就是必填的限制而已,不過既然預設支援那麼多,那不如就一個一個玩玩看吧。
public class RegisterModel { [Required]//必填 [StringLength(3,MinimumLength=2)]//最多三個字、最少兩個字 [Display(Name = "User name")] public string UserName { get; set; } [Required] [DataType(DataType.EmailAddress)] [Display(Name = "Email")] [RegularExpression(@"\w+\@\w+",ErrorMessage="Email格式錯誤")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "{0} 欄位最少 {2} 個字,最多 {1} 個字", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "密碼")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "密碼確認")] [Compare("Password", ErrorMessage = "兩次密碼不一樣")] public string ConfirmPassword { get; set; } }
將 RegisterModel 改成上方的規則後記得先編譯再前往註冊頁面試試看
就可以看到新的驗證規則都生效了
眼尖的朋友可能會發現, demo 少介紹一個 Remote ,沒錯!因為這個 Remote 比較特別因此抽出來說明,這個 Remote 的功能是讓前端去讀取後端的資料來驗證的,比如說剛剛的註冊會員功能,如果我們期待已經註冊過的 User Name 不能再被註冊,那上述介紹的任何一個驗證規則都無法勝任,因為驗證的邏輯牽扯到了資料庫中現有的資料,這種情況的時候就是使用 Remote 的時機,它可以利用 AJAX 的方式呼叫後端程式,由後端程式完成驗證後再傳回結果至前端,以下就是實作步驟。
首先建立一個 ValidateController 並且在裡面寫上要給 Remote 呼叫的 Action
public class ValidateController : Controller { public JsonResult CheckUserName(string userName) { bool isValidate = false; if (Url.IsLocalUrl(Request.Url.AbsoluteUri)) { //利用 IsLocalUrl檢查是否為網站呼叫的 //借此忽略一些不必要的流量 if (userName != "demoshop") { //因連資料庫麻煩 //所以假裝示範不可以註冊某一名字 isValidate = true; } } // Remote 驗證是使用 Get 因此要開放 return Json(isValidate, JsonRequestBehavior.AllowGet); } }
再來改變一下 RegisterModel 中的 UserName
[Required]//必填 [StringLength(10,MinimumLength=2)]//最多10個字、最少2個字 [Display(Name = "User name")] [Remote("CheckUserName","Validate",ErrorMessage="遠端驗證失敗")] public string UserName { get; set; }
此 Action 傳入的參數名稱必須要與你要驗證的屬性名稱一樣
編譯過後回到註冊頁面,當我們輸入了「demoshop」時會顯示「遠端驗證失敗」的字樣
開啟封包監控軟體(Firebug)查看第一次輸入「test」回傳的是「true」第二次輸入「demoshop」回傳的就是「false」了
ASP.NET MVC 最令人喜歡的就是擴充性, Remote 驗證也提供了一些空間讓我們發揮,試想假設今天註冊的驗證需求改了, UserName 和 Email 都不能重複,難道我們要傻傻的寫兩次並且一直回後端問嗎?這不是一個網頁程式設計師該妥協的,所以程式又改成這樣
public JsonResult CheckUserName(string userName, string email) { bool isValidate = false; if (Url.IsLocalUrl(Request.Url.AbsoluteUri)) { if (userName != "demoshop" && email != "1234") { isValidate = true; } } return Json(isValidate, JsonRequestBehavior.AllowGet); }
RegisterModel 因為操作流程所以將 Remote 驗證移至 Email 欄位上
[Required]//必填 [StringLength(10, MinimumLength = 2)]//最多10個字、最少2個字 [Display(Name = "User name")] public string UserName { get; set; } [Required] [DataType(DataType.EmailAddress)] [Display(Name = "Email")] [Remote("CheckUserName", "Validate", AdditionalFields = "UserName", ErrorMessage = "遠端驗證失敗")] public string Email { get; set; }
千萬注意使用 AdditionalFields 的指定名稱大小寫一定要和欄位名稱一樣,像本範例你寫 AdditionalFields = "username" 是不會過的。
編譯過後我們又回到註冊頁面
可以看到增加的欄位也利用 Querystring 傳到後端去了
如果要傳遞的欄位不只一個,可以利用逗點來區隔,此範例就再加上 Password
[Remote("CheckUserName", "Validate", AdditionalFields = "UserName,Password",ErrorMessage = "遠端驗證失敗")]
(這樣也是有想到的所以說彈性還真好...)
第一篇好像就有點長了先前研究的時間不算,光是寫這篇就已經花了我六顆番茄,所以就先介紹到這吧,再來的文章重點在擴充與修改,本系列文目前已經規劃了九篇,還請各位有空多多回來觀看。
回應討論