標籤:code ring logs 模型 需要 特性 jpg 也會 date
續我們前面所說的知識點進行下一個知識點的分析,這一次我們來說明一下資料驗證。其實這是個很容易理解並掌握的地方,但是這會浪費大家狠多的時間,所以我來總結整理一下,節約一下大家寶貴的時間。
在MVC 3中 資料驗證,已經應用的非常普遍,我們在web form時代需要在View端通過js來驗證每個需要驗證的控制項值,並且這種驗證的可用性很低。但是來到了MVC 新時代,我們可以通過MVC提供的資料驗證Attribute來進行我們的資料驗證。並且MVC 提供了用戶端和伺服器端 雙層的驗證,只有我們禁用了用戶端js以後,也會執行服務端驗證,所以大大提高了我們的開發進度。今天我們就一起以一個初學者的身份來進入資料驗證的殿堂。
首先,要使MVC 資料驗證在用戶端生效,我們必須匯入必要的js庫。其中我在一篇部落格中專門介紹了通過jquery.validate.js進行鏈式驗證的方式。
1 <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>2 <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>3 <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
然後我們就需要添加對應的Model ,其實在MVC中Model層對應的不一定是實體類,還可以是領域模型。這個區別還是存在的。我們添加一個簡單的User類,
1 namespace MvcApplication4.Models 2 { 3 public class UserInfo 4 { 5 //ID編號 6 [ScaffoldColumn(false)] 7 [Required(AllowEmptyStrings = false, ErrorMessage = "使用者ID不可為空")] 8 [Display(Name = "記錄編號", Order = 20000)] 9 public int ID { get; set; }10 11 [Display(Order = 15000)]12 [Required(AllowEmptyStrings = false, ErrorMessage = "使用者名稱不可為空")]13 [StringLength(20, MinimumLength = 6, ErrorMessage = "使用者名稱不能大於{2} 且要小於{1}")]14 [Remote("User", "Validate", HttpMethod = "post", ErrorMessage = "使用者名稱已經存在")]15 public string UserName { get; set; }16 17 18 [Display(Name="password")]19 [DataType(DataType.Password)]20 [Required(AllowEmptyStrings = false, ErrorMessage = "密碼不可為空")]21 [StringLength(60, MinimumLength = 20, ErrorMessage = "密碼必須在{2} 和{1}之間")]22 public string UserPassword { get; set; }23 24 [Required(AllowEmptyStrings = false, ErrorMessage = "郵箱必填")]25 [RegularExpression(@"[A-Za-z0-9._%+-][email protected][A-Za-z0-9]+\.[A-Za-z]{2,4}", ErrorMessage = "{0}的格式不正確")]26 public string Email { get; set; }27 28 [Compare("Email", ErrorMessage = "郵箱要相同")]29 public string TEmail { get; set; } //compare 大小寫要相同 否則不會觸發 驗證30 31 32 [Display(Name = "社會安全號碼碼")]33 [RegularExpression(@"\d{17}[\d|x]|\d{15}", ErrorMessage = "社會安全號碼碼格式錯誤")]34 public string IdentityNo { get; set; }35 36 [Required(AllowEmptyStrings = false, ErrorMessage = "年齡必填")]37 [Range(10, 100, ErrorMessage = "年齡不能大於{2} 不能小於{1}")]38 public int Age { get; set; }39 40 [ReadOnly(true)]41 [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:c}")]42 [Required(ErrorMessage = "金額不可為空")]43 [Range(typeof(decimal), "20.0", "30.0", ErrorMessage = "金額在{1}和{2}之間")]44 public decimal Money { get; set; }45 }46 }
在Model 層UserInfo類中,我們定義了一個User應該具有的屬性,以及需要為每個屬性添加的不同驗證。設定好了Model,我們就需要通過Controller來顯示對應的View層。
其實Controller不需要做任何的處理,只需要選擇一個合適的View進行頁面顯示。最重要的是在View層。
@{ 2 Layout = null; 3 } 4 @model MvcApplication4.Models.UserInfo 5 <!DOCTYPE html> 6 <html> 7 <head> 8 <title>Index</title> 9 </head>10 <body>11 <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>12 <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>13 <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>14 <div>15 @using (Html.BeginForm())16 { 17 @Html.ValidationSummary(true)18 <fieldset>19 <legend>UserInfo</legend>20 21 22 23 <div class="editor-label">24 @Html.LabelFor(t => t.UserPassword)25 </div>26 <div class="editor-field">27 @Html.EditorFor(model => model.UserPassword)28 @Html.ValidationMessageFor(model => model.UserPassword)29 </div>30 <div class="editor-label">31 @Html.LabelFor(t => t.IdentityNo)32 </div>33 <div class="editor-field">34 @Html.EditorFor(model => model.IdentityNo)35 @Html.ValidationMessageFor(model => model.IdentityNo)36 </div>37 <div class="editor-label">38 @Html.LabelFor(t => t.Email)39 </div>40 <div class="editor-field">41 @Html.EditorFor(model => model.Email)42 @Html.ValidationMessageFor(model => model.Email)43 </div>44 45 <div class="editor-label">46 @Html.LabelFor(t => t.Age)47 </div>48 <div class="editor-field">49 @Html.EditorFor(model => model.Age)50 @Html.ValidationMessageFor(model => model.Age)51 </div>52 53 <div class="editor-label">54 @Html.LabelFor(t => t.Money)55 </div>56 <div class="editor-field">57 @Html.EditorFor(model => model.Money)58 @Html.ValidationMessageFor(model => model.Money)59 </div>60 61 <div class="editor-label">62 @Html.LabelFor(t => t.TEmail)63 </div>64 <div class="editor-field">65 @Html.EditorFor(model => model.TEmail)66 @Html.ValidationMessageFor(model => model.TEmail)67 </div>68 69 @Html.EditorForModel()70 71 </fieldset>72 <input type="submit" value="提交" />73 }74 </div>75 </body>76 </html>
我在View層中定義了兩種顯示Model資料的方式,一種是通過html.EditorFor(model)來分別顯示每個不同的屬性,另外一個簡潔的方式就是通過html.EditorForModel()進行,這個方法會提供錯誤資訊顯示等。
Model 、View、Controller都設定好了,下面我們來看一下最終啟動並執行效果。
在中,我們看到了兩個相同的部分,這是我採用兩個不同的顯示方式顯示的效果。其中有兩個Age,這兩個只要一個驗證通過,就會驗證通過。根本原因就是它們的ID值是相同的。
看到了實際效果,我們來逐個分析一下每個驗證Attribute的實現方式 極其注意方式。
Required 必填項 表示的是這個欄位值是必填的。
[Required(AllowEmptyStrings = false, ErrorMessage = "使用者名稱不可為空")]
Display 欄位顯示的名稱 表示該欄位顯示的是Name值,而不是欄位本身的名稱
[Display(Name="password")]
StringLength 表示的是驗證字串的長度。我們可以設定最小長度和最大長度,如果不在這個範圍內,則會提示錯誤資訊
[StringLength(20, MinimumLength = 6, ErrorMessage = "使用者名稱不能大於{2} 且要小於{1}")]
其中我們看到ErrorMessage中有預留位置存在,其實這個預留位置很容易理解,就是{0}表示的是欄位本身的名稱,{1}表示它前面的第一個參數,{2}表示它前面的第二個參數。
ScaffoldColumn 表示的是是否採用MVC架構來處理 設定為true表示採用MVC架構來處理,如果設定為false,則該欄位不會在View層顯示,裡面定義的驗證也不會生效。
[ScaffoldColumn(false)]
Remote 表示的是進行遠端驗證,這個相當於我們採用ajax方式來非同步請求伺服器,並返回資訊。最常用的就是驗證使用者名稱是否重複。下面這個驗證是非同步呼叫ValidateController下面的User Action 並且返回結果為json值。
[Remote("User", "Validate", HttpMethod = "post", ErrorMessage = "使用者名稱已經存在")]
DataType 表示的是欄位的資料類型 這個會影響到欄位在View層的顯示效果。如果設定為password,則輸入時會用*替換。
[DataType(DataType.Password)]
RegularExpression Regex驗證。Regex我曾經在我的一篇部落格中有所介紹。Regex是驗證字串的利器,我們必須掌握的。前面是驗證模式,後面是出錯顯示的錯誤資訊。
使用Regex抓取部落格園列表資料
[RegularExpression(@"[A-Za-z0-9._%+-][email protected][A-Za-z0-9]+\.[A-Za-z]{2,4}", ErrorMessage = "{0}的格式不正確")]
Compare 比較兩個欄位值是否相同,這個如果我們採用js進行驗證的話,最少需要三行,這還只是用戶端驗證。那麼在MVC中就比較容易實現了。
[Compare("Email", ErrorMessage = "郵箱要相同")]
在Compare 驗證中有一個地方需要注意,就是第一個參數,它是另一個欄位的名稱,我們一定要注意大小寫正確,如果錯誤的話,驗證就不會通過的。
Range 表示的大小資料的大小驗證。這個Attribute可以驗證int,double,decimal等資料類型的值的大小範圍。 表示的是在10和100之間,包括10和100
[Range(10, 100, ErrorMessage = "年齡不能大於{2} 不能小於{1}")]
ReadOnly 表示欄位是否唯讀。 這個在View層我有時測試會沒有執行。具體原因還未知。
DisplayFormat 表示的資料顯示的樣式。其實這個不屬於資料驗證特性,而應該屬於資料格式。如果要啟用格式設定,第一個參數一定要設定為true,第二個就和我們toString()方法後面的參數一樣。
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:c}")]
UiHint 告訴MVC 指定的模版。
HiddenInput 隱藏欄位顯示
其實我個人是將資料驗證的這些特性分為兩類,一類是真正的進行驗證,Required,Range,StringLength,Display,Remote,RegularExpression,Compare,Range。這些特性是真正會進行驗證的Attribute。另外幾個Display,ReadOnly,DataType,DisplayFormat,ScaffoldColumn等和欄位的顯示有關,沒有真正的和伺服器端進行驗證。
我們可以使用MVC提供的各種驗證特性,那麼我們是否可以自己來定義自訂特性驗證呢。MVC有著巨大的可擴充性,我們也可以自己進行擴充,有兩種擴充方式,一種就是可以重複使用的和MVC架構中驗證,只要繼承自ValidationAttribute 就可以實現重複使用的驗證特性,另一種就是內包含的模式,它是只驗證特定的Model,繼承自IValidatableObject可以實現字包含的驗證。
可重複使用的驗證特性,繼承自ValidationAttribute。
1 public class MaxWordsAttribute : ValidationAttribute 2 { 3 4 public MaxWordsAttribute(int maxWords) 5 : base("{0} 字串過長") 6 { 7 _maxWords = maxWords; 8 } 9 private readonly int _maxWords;10 11 protected override ValidationResult IsValid(object value, ValidationContext validationContext)12 {13 if (value != null)14 {15 var valueAsString = value.ToString();16 if (valueAsString.Split(‘ ‘).Length > _maxWords)17 {18 var errorMessage = FormatErrorMessage(19 validationContext.DisplayName);20 return new ValidationResult(errorMessage);21 }22 }23 return ValidationResult.Success;24 }25 }
MVC 驗證特性提高了我們開發的效率以及穩定性,值得我們學習。還是那句話,每天學一學,自己常進步,世界更美好。
MVC 的驗證擴充特性 以及全球化,我們在以後有機會在一起學習。
MVC 3 資料驗證 Model Validation 詳解