MVC 3 數據驗證 Model Validation 詳解


繼續我們前面所說的知識點進行下一個知識點的分析,這一次我們來說明一下數據驗證。其實這是個很容易理解並掌握的地方,但是這會浪費大家狠多的時間,所以我來總結整理一下,節約一下大家寶貴的時間。

在MVC 3中 數據驗證,已經應用的非常普遍,我們在web form時代需要在View端通過js來驗證每個需要驗證的控件值,並且這種驗證的可用性很低。但是來到了MVC 新時代,我們可以通過MVC提供的數據驗證Attribute來進行我們的數據驗證。並且MVC 提供了客戶端和服務器端 雙層的驗證,只有我們禁用了客戶端js以后,也會執行服務端驗證,所以大大提高了我們的開發進度。今天我們就一起以一個初學者的身份來進入數據驗證的殿堂。

首先,要使MVC 數據驗證在客戶端生效,我們必須導入必要的js庫。其中我在一篇博客中專門介紹了通過jquery.validate.js進行鏈式驗證的方式。

通過擴展方法 鏈式方法 為MVC 3 視圖添加驗證

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._%+-]+@[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層。

 1 @{
 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 正則表達式驗證。正則表達式我曾經在我的一篇博客中有所介紹。正則表達式是驗證字符串的利器,我們必須掌握的。前面是驗證模式,后面是出錯顯示的錯誤信息。

使用正則表達式抓取博客園列表數據 

 [RegularExpression(@"[A-Za-z0-9._%+-]+@[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 的驗證擴展特性 以及全球化,我們在以后有機會在一起學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM