一.學習前的一句話
在這裡要先感謝那些能夠點開我隨筆的博友們。慢慢的已經在部落格園中度過一年半了,伊始只是將部落格園作為自己學習的記錄本一樣使用,也不敢將自己的隨筆發表到部落格園首頁,生怕自己的技藝不高,反倒成了笑話。但是隨著時間的推移,再也按捺不住這種想法,於是就寫了一篇隨筆發表到部落格園首頁。讓我意想不到的是有許多人都看了,而且也留下了評論。這讓我鼓起勇氣寫了第二、三、四篇。到現在的連載,這裡我希望那些從未發表過隨筆的人可以嘗試去發表,在這裡他人不會嘲諷你,而是會給你更好的建議。說了這麼多下面我們繼續開始學習ASP.NET MVC吧。
二.準備工作
1、建立一個ASP.NET MVC 4網站(筆者的命名是MvcStudy)
2、在Models下建立一個Register模型類,具體程式碼如下所示:
1 namespace MvcStudy.Models 2 { 3 public class Register 4 { 5 public String UserName { get; set; } 6 public String Password { get; set; } 7 public String RptPassword { get; set; } 8 public String Email { get; set; } 9 public DateTime BirthDate { get; set; } 10 public bool IsApprove { get; set; } 11 } 12 }
3、建立一個名為Home的控制器,並在其中寫入下面的程式碼:
1 namespace MvcStudy.Controllers 2 { 3 public class HomeController : Controller 4 { 5 public ActionResult Index() 6 { 7 return View(); 8 } 9 10 [HttpPost] 11 public ActionResult Index(Register reg) 12 { 13 return View(); 14 } 15 } 16 }
4、接著在Views下建立一個Home資料夾並在其中新建一個Index檢視,程式碼如下:
1 @model MvcStudy.Models.Register 2 @{ 3 ViewBag.Title = "Index"; 4 } 5 6 7 @using (Html.BeginForm()) 8 { 9 <div> 10 使用者名稱: 11 @Html.EditorFor(m => m.UserName) 12 </div> 13 <div> 14 密碼: 15 @Html.EditorFor(m => m.Password) 16 </div> 17 <div> 18 重複密碼: 19 @Html.EditorFor(m => m.RptPassword) 20 </div> 21 <div> 22 出生日期: 23 @Html.EditorFor(m => m.BirthDate) 24 </div> 25 <div> 26 郵箱: 27 @Html.EditorFor(m => m.Email) 28 </div> 29 <div> 30 @Html.EditorFor(m => m.IsApprove) 31 同意相關條約 32 </div> 33 <div> 34 <input type="submit" value="註冊" /> 35 </div> 36 }
5、因為後面要用到客戶端驗證,所以這裡我們先把需要引用需要的js庫(在Views/Shared/_Layout.cshtml中寫入):
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <meta name="viewport" content="width=device-width" /> 6 <title>@ViewBag.Title</title> 7 @Styles.Render("~/Content/css") 8 @Scripts.Render("~/bundles/modernizr") 9 @Scripts.Render("~/bundles/lufy") 10 </head> 11 <body> 12 13 @RenderBody() 14 15 @Scripts.Render("~/bundles/jquery") 16 @Scripts.Render("~/bundles/jqueryval") 17 @RenderSection("scripts", required: false) 18 </body> 19 </html>
PS:為了確保正確,請讀者驗證下web.config中的以下屬性的值是否跟筆者的一樣:
三.常規驗證
相信很多從事ASP.NET的開發者在對資料的驗證上基本都是用的ASP.NET自帶的驗證控制元件,同時在後臺還會通過N多個if語句再去判斷,所以在ASP.NET MVC的常規驗證跟這個一樣,唯一的區別就是錯誤的資訊輸出不需要我們自己實現了,下面我們修改Home控制器中的Index(Register reg)動作:
1 [HttpPost] 2 public ActionResult Index(Register reg) 3 { 4 if (String.IsNullOrEmpty(reg.UserName)) 5 { 6 ModelState.AddModelError("UserName", "使用者名稱不能為空"); 7 } 8 else if (reg.UserName.Length < 6) 9 { 10 ModelState.AddModelError("UserName", "使用者名稱長度不能小於6位"); 11 } 12 if (ModelState.IsValidField("BirthDate") && reg.BirthDate > DateTime.Now) 13 { 14 ModelState.AddModelError("BirthDate", "生日不能為將來的時間"); 15 } 16 if (ModelState.IsValid) 17 { 18 //儲存資料 19 } 20 return View(); 21 }
上面我們簡單的判斷了使用者名稱是否為空,長度是否小於6,以及出生日期是否填寫的為將來的日期,接著我們還要在Index檢視中加入@Html.ValidationSummary(),這樣我們才能夠看到最後的輸出的錯誤資訊,編譯然後不輸入任何內容點選註冊之後將會出現下面的情況:
我們會發現表單壓根就提交不了,這是因為客戶端驗證在工作。獲取讀者會很奇怪這節只是常規驗證,這個是因為出生日期的格式是DateTime是不能為NULL的,而ASP.NET MVC預設情況下就已經為我們做好了。隨便輸入123到出生日期然後點選註冊,頁面會反饋下面的錯誤資訊:
第一個資訊就是我們在控制器中通過if判斷語句加進去的,而第二個似乎你會困惑是怎麼回事,這是因為模型繫結器中會為我們進行簡單的驗證,比如日期不能為空,並且日期的格式要正確,這個都是預設的行為。我們可以嘗試在使用者名稱中輸入123,同時出生日期輸入2020/1/1,點選註冊,這時候的錯誤資訊都是我們新增的了:
讀者使用過很多系統,錯誤資訊基本上都是顯示在對應的輸入框的右邊,在ASP.NET MVC中一樣可以判斷,下面我們修改Index檢視:
1 <div> 2 使用者名稱: 3 @Html.EditorFor(m => m.UserName) 4 @Html.ValidationMessageFor(m => m.UserName) 5 </div> 6 <div> 7 出生日期: 8 @Html.EditorFor(m => m.BirthDate) 9 @Html.ValidationMessageFor(m => m.BirthDate) 10 </div>
這個時候我們在重新提交,錯誤資訊就到右邊了。但是筆者還不打算結束掉這節,我如果限制使用者名稱不能為100000怎麼辦呢?或許讀者馬上就能寫出來,但是這個是模型級的錯誤,並不是針對這個欄位,所以我們在Home控制器的Index方法(響應Post的那個)中繼續追加:
接著修改Index檢視:
然後重新編譯,使用者名稱輸入100000就可以看到下面的結果:
這樣我們就可以結束這節了。
四.採用註解屬性的驗證
上面這種方式的驗證雖然簡單,很多人都能夠立馬上手,但是看到動作中N多個if語句的確不是個滋味,在這個炎炎夏日會讓人非常暴躁,這節我們就來簡單的方法來解決這些問題,為我們降溫,我們修改Register模型類:
1 namespace MvcStudy.Models 2 { 3 public class Register 4 { 5 [Required(ErrorMessage="使用者名稱必須填寫")] 6 [MinLength(6,ErrorMessage="使用者名稱長度過短")] 7 public String UserName { get; set; } 8 [DataType(DataType.Password)] 9 public String Password { get; set; } 10 [DataType(DataType.Password)] 11 [Compare("Password",ErrorMessage="密碼要一致")] 12 public String RptPassword { get; set; } 13 public String Email { get; set; } 14 public DateTime BirthDate { get; set; } 15 public bool IsApprove { get; set; } 16 } 17 }
筆者在這裡還判斷了密碼和重複密碼是否相同,關於DataType可以參考筆者寫的模型繫結,下面重新編譯,然後開啟頁面測試,就可以發現這些驗證都實現了,因為筆者這裡預設開啟了客戶端驗證所以在未驗證通過的情況下無法提交表單。但是我們發現現有的驗證註解屬性沒法實現顯示出生日期不能為將來實現,所以下面一節我們還要學習自定義驗證註解屬性。
五.自定義驗證註解屬性
通過上節我們已經能夠使用ASP.NET MVC自帶的驗證屬性來完成一些簡單的驗證,正如上節最後所說的那樣,對於一部分驗證自帶的已經無法滿足我們的需求了,那麼我們就需要通過自定義的方式來解決,下面我們自定義一個註解屬性來解決上節遺留下來的問題,首先我們新建一個Validation資料夾,然後在該資料夾下面新建一個FutureTimeAttribute類,程式碼如下所示:
1 namespace MvcStudy.Validation 2 { 3 public class FutureTimeAttribute : ValidationAttribute 4 { 5 public override bool IsValid(object value) 6 { 7 DateTime dt = (DateTime)value; 8 if (dt != null) 9 { 10 if (dt < DateTime.Now) 11 { 12 return true; 13 } 14 } 15 return false; 16 } 17 } 18 }
接著我們就可以運用到對應的屬性上面了
重新編譯,然後填寫一個將來的時間點選註冊之後我們將會看到如下的結果:
通過這節的補充,相信大家此時此刻酷爽嗎?當然還有一部分人還需要更實現更復雜的驗證判斷,而且是針對特定的模型類實現的,並不適合採用上面這種方式,那麼下節會非常符合你的胃口。
PS:讀者不僅僅可以通過繼承ValidationAttribute,同時還可以繼承其他現有的驗證註解屬性,比如RequiredAttribute等。
六.模型與驗證合二為一
我們可以發現筆者之前不是顯示使用者名稱不能為100000嗎,但是我並沒有將這個作為註解屬性而寫,因為註解屬性一般適合於很多地方都需要使用這種驗證才適合,但是這個限制僅僅只是針對這個模型類,而其他的模型類並不需要。那麼我們就需要一中能夠與模型類緊密相關的驗證,而解決方案就是讓模型類實現IValidatableObject介面的Validate方法即可,比如下面筆者將實現限制使用者名稱不能為100000的情況:
1 namespace MvcStudy.Models 2 { 3 public class Register : IValidatableObject 4 { 5 [Required(ErrorMessage="使用者名稱必須填寫")] 6 [MinLength(6,ErrorMessage="使用者名稱長度過短")] 7 public String UserName { get; set; } 8 [DataType(DataType.Password)] 9 public String Password { get; set; } 10 [DataType(DataType.Password)] 11 [Compare("Password",ErrorMessage="密碼要一致")] 12 public String RptPassword { get; set; } 13 public String Email { get; set; } 14 [FutureTimeAttribute(ErrorMessage="時間不能為將來")] 15 public DateTime BirthDate { get; set; } 16 public bool IsApprove { get; set; } 17 18 public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 19 { 20 var result = new List<ValidationResult>(); 21 if (UserName == "100000") 22 { 23 result.Add(new ValidationResult("使用者名稱不能為100000")); 24 } 25 return result; 26 } 27 } 28 }
然後我們重新編譯,使用者名稱輸入為100000就可以看到這個錯誤了:
七.客戶端驗證
其實前面幾節一直都在使用客戶端驗證,本該這節是不需要的,但是我們可以發現郵箱部分還沒有驗證,讀者可能會認為應該使用RegularExpression來驗證,但是學過jquery驗證庫的人應該知道這個庫已經自帶了專門的驗證,而這節就是用來手動使用這個驗證的,我們開啟Index檢視修改郵箱部分:
1 <div> 2 郵箱: 3 @Html.TextBoxFor(m => m.Email, new 4 { 5 data_val = "true", 6 data_val_email = "郵箱格式錯誤", 7 data_val_required = "請輸入郵箱" 8 }) 9 @Html.ValidationMessageFor(m => m.Email) 10 </div>
重新整理頁面,這個時候我們發現郵箱也可以驗證了:
相信很多喜歡客戶端開發而不是服務端開發人員來說,這種方式對於你們來說更快捷,但是對於服務端開發者來說,並不需要氣餒,ASP.NET MVC也提供對應的方法,下節我們將用服務端的方式來實現同樣的效果。
八.自定義客戶端驗證
這裡筆者就不多說廢話了直接上程式碼,我們自己實現一個郵箱驗證屬性,而且還能夠支援客戶端驗證,首先在Valudation資料夾下新建一個EmailAttribute類,並在其中寫入如下程式碼:
1 namespace MvcStudy.Validation 2 { 3 public class EmailAttribute : ValidationAttribute , IClientValidatable 4 { 5 6 public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 7 { 8 return new List<ModelClientValidationRule> 9 { 10 new ModelClientValidationRule{ 11 ValidationType = "email", 12 ErrorMessage = "請輸入正確的郵箱" 13 } 14 }; 15 } 16 } 17 }
PS:為了能夠符合本節,所以筆者就沒有將服務端的驗證程式碼寫到其中,如果讀者需要在真實場合中使用務必將服務端的驗證也要加上去。
下面我們就在Email中加上這個註解屬性並重新編譯,我們可以看到最後頁面的效果跟上一節的效果是完全一致的。
九.結束語
其實筆者並不才,但是擁有非常大的興趣,而今已經是習慣了。每天總是要看上那麼些技術方面的書,寫上幾段程式碼,當然還不少謝謝隨筆和大家分享啦!