概述html
在模型中添加驗證規則正則表達式
自定義驗證規則數據庫
夥伴類的使用ide
總結工具
[Asp.net MVC]Asp.net MVC5系列——第一個項目post
[Asp.net MVC]Asp.net MVC5系列——添加視圖測試
[Asp.net MVC]Asp.net MVC5系列——添加模型ui
[Asp.net MVC]Asp.net MVC5系列——從控制器訪問模型中的數據this
[Asp.net MVC]Asp.net MVC5系列——添加數據url
上篇文章中介紹了添加數據,在提交表單的數據的時候,咱們須要對數據的合法性進行校驗,Asp.net MVC5中,提供一種方便的驗證方式。本文介紹如何在咱們的Student模型中添加一些驗證規則,同時確認當用戶使用咱們的應用程序建立或編輯學生信息時將使用這些驗證規則對用戶輸入的信息進行檢查。
DRY原則
在ASP.NET MVC中,有一條做爲核心的原則,就是DRY(「Don’t Repeat Yourself,中文意思爲:不要讓開發者重複作一樣的事情)原則。ASP.NET MVC提倡讓開發者「一處定義、到處可用」。這樣能夠減小開發者的代碼編寫量,同時也更加便於代碼的維護。
首先,讓咱們在Student類中追加一些驗證規則。
打開Student.cs文件,在文件的頭部追加一條引用System.ComponentModel.DataAnnotations命名空間的using語句,代碼以下所示。
1 using System.ComponentModel.DataAnnotations;
這個System.ComponentModel.DataAnnotations命名空間是.NET Framework中的一個命名空間。它提供了不少內建的驗證規則,你能夠對任何類或屬性顯式指定這些驗證規則。
如今讓咱們來修改Student類,增長一些內建的Required(必須輸入),StringLength(輸入字符長度)與Range(輸入範圍)驗證規則,固然,咱們也能夠自定義咱們本身的驗證規則,以後會說明如何建立自定義驗證規則。
1 //------------------------------------------------------------------------------ 2 // <auto-generated> 3 // 此代碼已從模板生成。 4 // 5 // 手動更改此文件可能致使應用程序出現意外的行爲。 6 // 若是從新生成代碼,將覆蓋對此文件的手動更改。 7 // </auto-generated> 8 //------------------------------------------------------------------------------ 9 10 namespace Wolfy.FirstMVCProject.Models 11 { 12 using System; 13 using System.Collections.Generic; 14 using System.ComponentModel.DataAnnotations; 15 16 public partial class Student 17 { 18 public Student() 19 { 20 this.Score = new HashSet<Score>(); 21 } 22 23 public int stuId { get; set; } 24 [Required(ErrorMessage = "必須輸入標題")] 25 public string stuName { get; set; } 26 27 public string stuSex { get; set; } 28 public System.DateTime stuBirthdate { get; set; } 29 public System.DateTime stuStudydate { get; set; } 30 [StringLength(4, ErrorMessage = "只能輸入4個字符")] 31 public string stuAddress { get; set; } 32 [Required(ErrorMessage = "必須輸入標題")] 33 //正則驗證 34 [RegularExpression(@"^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$", ErrorMessage = "郵箱格式不正確")] 35 public string stuEmail { get; set; } 36 [RegularExpression(@"\d{11}", ErrorMessage = "郵箱格式不正確")] 37 public string stuPhone { get; set; } 38 public Nullable<bool> stuIsDel { get; set; } 39 public Nullable<System.DateTime> stuInputtime { get; set; } 40 public int classId { get; set; } 41 42 public virtual Course Course { get; set; } 43 public virtual ICollection<Score> Score { get; set; } 44 } 45 }
上述這些驗證屬性指定了咱們想要強加給模型中各屬性的驗證規則。Required屬性表示必需要指定一個屬性值,在上例中,一個有效的學生信息必須含有標題,地址,電話,郵箱。Range屬性表示屬性值必須在一段範圍之間。StringLength屬性表示一個字符串屬性的最大長度或最短長度。
Action中的代碼
1 [HttpPost] 2 public ActionResult Create(Student student) 3 { 4 //ModelState.IsValid校驗客戶端數據是否所有符合驗證規則 5 if (ModelState.IsValid) 6 { 7 //獲取dropdownlist選中的value值 8 string strClassID = Request.Form["class"]; 9 int intId = Convert.ToInt32(strClassID); 10 var course = from c in entity.Course 11 where c.classId == intId 12 select c; 13 //處理外鍵關係 14 student.Course = course.FirstOrDefault(); 15 entity.Student.Add(student); 16 entity.SaveChanges(); 17 return RedirectToAction("Index"); 18 19 } 20 else 21 { 22 //在不符合驗證規則的時候,得從新綁定DropDownList數據源。 23 var courses = from s in entity.Course 24 select s; 25 List<SelectListItem> items = new List<SelectListItem>(); 26 foreach (var item in courses) 27 { 28 SelectListItem selectListItem = new SelectListItem() { Text = item.className, Value = item.classId.ToString() }; 29 items.Add(selectListItem); 30 } 31 ViewData["class"] = items; 32 return View(student); 33 } 34 }
運行效果
若是上面的驗證規則,不能知足須要,能夠本身定義驗證規則,首先看一下,Required是如何實現的,我們就模仿Required來實現一個本身的驗證規則。
1 namespace System.ComponentModel.DataAnnotations 2 { 3 // 摘要: 4 // 指定須要數據字段值。 5 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] 6 public class RequiredAttribute : ValidationAttribute 7 { 8 // 摘要: 9 // 初始化 System.ComponentModel.DataAnnotations.RequiredAttribute 類的新實例。 10 public RequiredAttribute(); 11 12 // 摘要: 13 // 獲取或設置一個值,該值指示是否容許空字符串。 14 // 15 // 返回結果: 16 // 若是容許空字符串,則爲 true;不然爲 false。 默認值爲 false。 17 public bool AllowEmptyStrings { get; set; } 18 19 // 摘要: 20 // 檢查必填數據字段的值是否不爲空。 21 // 22 // 參數: 23 // value: 24 // 要驗證的數據字段值。 25 // 26 // 返回結果: 27 // 若是驗證成功,則爲 true;不然爲 false。 28 // 29 // 異常: 30 // System.ComponentModel.DataAnnotations.ValidationException: 31 // 數據字段值爲 null。 32 public override bool IsValid(object value); 33 } 34 }
1 // 摘要: 2 // 做爲全部驗證屬性的基類。 3 // 4 // 異常: 5 // System.ComponentModel.DataAnnotations.ValidationException: 6 // 在設置非本地化 System.ComponentModel.DataAnnotations.ValidationAttribute.ErrorMessage 7 // 屬性錯誤消息的同時,本地化錯誤消息的 System.ComponentModel.DataAnnotations.ValidationAttribute.ErrorMessageResourceType 8 // 和 System.ComponentModel.DataAnnotations.ValidationAttribute.ErrorMessageResourceName 9 // 屬性也被設置。 10 public abstract class ValidationAttribute : Attribute 11 { 12 //其餘代碼 13 }
因此,驗證規則特性必須集成ValidationAttribute類,固然也能夠繼承該類的子類。(注意:對於特性約定以Attribute結尾)。
咱們就自定義一個驗證類,實現默認值約束規則DefaultsAttribute,而實現最簡單的方式就是自定義正則表達式的規則。
定義的驗證類的代碼以下:
1 public class DefaultsAttribute : RegularExpressionAttribute 2 { 3 public DefaultsAttribute() 4 : base("[mf]") 5 { 6 7 } 8 public override string FormatErrorMessage(string name) 9 { 10 return "性別只能輸入m(男)或者f(女)"; 11 } 12 }
爲Student類中的stuSex加上特性。
1 [Defaults] 2 public string stuSex { get; set; }
而後測試一下,看看實現效果
在Create視圖(追加學生信息視圖)與Create方法內部是如何實現驗證的?
該方法中的ModelState.IsValid屬性用來判斷是否提交的學生信息數據中包含有任何沒有經過數據驗證的無效數據。若是存在無效數據,Create方法從新返回追加學生信息視圖。若是數據所有有效,則將該條數據保存到數據庫中。
咱們以前建立的使用支架模板的Create.cshtml視圖模板中的代碼顯示以下,在首次打開追加學生信息視圖與數據沒有經過驗證時,Create方法中返回的視圖都是使用的這個視圖模板。
1 @model Wolfy.FirstMVCProject.Models.Student 2 3 @{ 4 Layout = null; 5 } 6 7 <!DOCTYPE html> 8 9 <html> 10 <head> 11 <meta name="viewport" content="width=device-width" /> 12 <title>Create</title> 13 </head> 14 <body> 15 @using (Html.BeginForm("Create","Student",FormMethod.Post)) 16 { 17 @Html.AntiForgeryToken() 18 19 <div class="form-horizontal"> 20 <h4>Student</h4> 21 <hr /> 22 @Html.ValidationSummary(true) 23 24 <div class="form-group"> 25 @Html.LabelFor(model => model.stuName, new { @class = "control-label col-md-2" }) 26 <div class="col-md-10"> 27 @Html.EditorFor(model => model.stuName) 28 @Html.ValidationMessageFor(model => model.stuName) 29 </div> 30 </div> 31 32 <div class="form-group"> 33 @Html.LabelFor(model => model.stuSex, new { @class = "control-label col-md-2" }) 34 <div class="col-md-10"> 35 @Html.EditorFor(model => model.stuSex) 36 @Html.ValidationMessageFor(model => model.stuSex) 37 </div> 38 </div> 39 40 <div class="form-group"> 41 @Html.LabelFor(model => model.stuBirthdate, new { @class = "control-label col-md-2" }) 42 <div class="col-md-10"> 43 @Html.EditorFor(model => model.stuBirthdate) 44 @Html.ValidationMessageFor(model => model.stuBirthdate) 45 </div> 46 </div> 47 48 <div class="form-group"> 49 @Html.LabelFor(model => model.stuStudydate, new { @class = "control-label col-md-2" }) 50 <div class="col-md-10"> 51 @Html.EditorFor(model => model.stuStudydate) 52 @Html.ValidationMessageFor(model => model.stuStudydate) 53 </div> 54 </div> 55 56 <div class="form-group"> 57 @Html.LabelFor(model => model.stuAddress, new { @class = "control-label col-md-2" }) 58 <div class="col-md-10"> 59 @Html.EditorFor(model => model.stuAddress) 60 @Html.ValidationMessageFor(model => model.stuAddress) 61 </div> 62 </div> 63 64 <div class="form-group"> 65 @Html.LabelFor(model => model.stuEmail, new { @class = "control-label col-md-2" }) 66 <div class="col-md-10"> 67 @Html.EditorFor(model => model.stuEmail) 68 @Html.ValidationMessageFor(model => model.stuEmail) 69 </div> 70 </div> 71 72 <div class="form-group"> 73 @Html.LabelFor(model => model.stuPhone, new { @class = "control-label col-md-2" }) 74 <div class="col-md-10"> 75 @Html.EditorFor(model => model.stuPhone) 76 @Html.ValidationMessageFor(model => model.stuPhone) 77 </div> 78 </div> 79 80 <div class="form-group"> 81 @Html.LabelFor(model => model.stuIsDel, new { @class = "control-label col-md-2" }) 82 <div class="col-md-10"> 83 @Html.EditorFor(model => model.stuIsDel) 84 @Html.ValidationMessageFor(model => model.stuIsDel) 85 </div> 86 </div> 87 88 <div class="form-group"> 89 @Html.LabelFor(model => model.stuInputtime, new { @class = "control-label col-md-2" }) 90 <div class="col-md-10"> 91 @Html.EditorFor(model => model.stuInputtime) 92 @Html.ValidationMessageFor(model => model.stuInputtime) 93 </div> 94 </div> 95 96 <div class="form-group"> 97 @Html.LabelFor(model => model.Course.classId, "stuClass", new { @class = "control-label col-md-2" }) 98 <div class="col-md-10"> 99 @Html.DropDownList("class", String.Empty) 100 @Html.ValidationMessageFor(model => model.classId) 101 </div> 102 </div> 103 104 <div class="form-group"> 105 <div class="col-md-offset-2 col-md-10"> 106 <input type="submit" value="Create" class="btn btn-default" /> 107 </div> 108 </div> 109 </div> 110 } 111 112 <div> 113 @Html.ActionLink("Back to List", "Index") 114 </div> 115 </body> 116 </html>
請注意在這段代碼中使用了許多Html.EditorFor幫助器來爲Student類的每一個屬性輸出一個輸入文本框。在每一個Html.EditorFor幫助器以後緊跟着一個Html.ValidationMessageFor幫助器。這兩個幫助器將與從控制器傳入的模型類的對象實例(在本示例中爲Student對象的一個實例)結合起來,自動尋找指定給模型的各個驗證屬性,而後顯示對應的驗證錯誤信息。
這種驗證體制的好處是在於控制器和Create視圖(追加學生信息視圖)事先都即不知道實際指定的驗證規則,也不知道將會顯示什麼驗證錯誤信息。驗證規則和錯誤信息只在Student類中被指定。
若是咱們以後想要改變驗證規則,咱們也只要在一處地方進行改變就能夠了。咱們不用擔憂整個應用程序中存在驗證規則不統一的問題,全部的驗證規則均可以集中在一處地方進行指定,而後在整個應用程序中使用這些驗證規則。這將使咱們的代碼更加清晰明確,更加具備可讀性、可維護性與可移植性。這將意味着咱們的代碼是真正符合DRY原則(一處指定,處處可用)的。
這個demo中,咱們使用的是EF的方式操做數據庫的,若是數據庫中表的字段有變化時,咱們就要更新模型,如圖所示:
若是從數據庫中更新模型,就會把上面添加的規則給替換掉,那麼以前寫的驗證規則就白費了,那麼有沒有解決辦法呢?辦法是有的,就是將要說的夥伴類。夥伴類的定義以下,
1 public class StudentValidate 2 { 3 public int stuId { get; set; } 4 [Required(ErrorMessage="姓名是必須的")] 5 public string stuName { get; set; } 6 public string stuSex { get; set; } 7 public System.DateTime stuBirthdate { get; set; } 8 public System.DateTime stuStudydate { get; set; } 9 public string stuAddress { get; set; } 10 public string stuEmail { get; set; } 11 public string stuPhone { get; set; } 12 public Nullable<bool> stuIsDel { get; set; } 13 public Nullable<System.DateTime> stuInputtime { get; set; } 14 public int classId { get; set; } 15 } 16 //指定要與數據模型類關聯的元數據類。 17 [MetadataType(typeof(StudentValidate))] 18 public partial class Student 19 { 20 21 } 22 }
本文介紹了表單驗證的方式,固然,你也可使用客戶端的校驗方式,表單驗證插件也挺多的,這裏就再也不贅述了。另外介紹了自定義的驗證規則,在驗證方式不符合本身要求的時候,能夠自定義一個驗證規則,固然你能夠直接使用正則表達式的驗證規則,可是若是這個驗證規則常用,那麼將它定義爲一個規則特性,像使用Required同樣去使用,是否是更方便?在文章最後,介紹了一種因爲更新model形成原來的model改變,修改了原來的驗證規則,能夠經過夥伴類來保證原來的驗證規則不變,又能更新model。