起飛網 ASP.NET MVC 5 學習教程目錄:
- 添加控制器
- 添加視圖
- 修改視圖和布局頁
- 控制器傳遞數據給視圖
- 添加模型
- 創建連接字符串
- 通過控制器訪問模型的數據
- 生成的代碼詳解
- 使用 SQL Server LocalDB
- Edit方法和Edit視圖詳解
- 添加查詢
- Entity Framework 數據遷移之添加字段
- 添加驗證
- Details 和 Delete 方法詳解
在本節中,我們將為Movie模型添加驗證邏輯,並確認驗證規則在用戶試圖使用程序創建和編輯電影時有效。
DRY 原則
ASP.NET MVC 的一個核心原則是DRY(Don't Repeat Yourself - 不做重復的事情)。ASP.NET MVC 鼓勵你一次性的指定功能或行為,然后應用程序的其它地方通過映射得到它,這樣一來就減少了大量的代碼,從而減少了出錯誤的可能性,並且更易於維護。
ASP.NET MVC 和 Entity Framework Code First 提供的驗證能是 DRY 原則的不錯的實踐。你可以在一處(在模型類中)定義驗證規則,從而在應用程序中的所有地方都可以使用這個規則。
接下來讓我們看看如何在現在的Movie 中添加高級的驗證規則吧。
為模型添加驗證規則
現在我們開始為Movie類添加一些驗證規則。
打開文件 Movie.cs,注意命名空間 System.ComponentModel.DataAnnotations 並不包含 System.Web。DataAnnotations 提供了內置的驗證特性,你可以將它們用在任何類或屬性中(它還包含了像DataType這樣的格式化的特性,它們不參與任何驗證)。
為Movie類添加一些內置的驗證規則,修改后的代碼如下:
代碼清單1:添加了驗證規則的Movie類
public class Movie { public int ID { get; set; } [Required] [StringLength(60, MinimumLength = 3)] public string Title { get; set; } [Display(Name = "Release Date")] [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } [Required] public string Genre { get; set; } [Range(1, 100)] [DataType(DataType.Currency)] public decimal Price { get; set; } [StringLength(5)] [Required] public string Rating { get; set; } }
使用數據遷移來更新數據庫結構。編譯解決方案,然后打開“程序包管理器控制台”窗口,執行下面的命令:
add-migration DataAnnotations
update-database
當這兩個命令執行完成之后,Visual Studio 為我們創建了 DataAnnotations 類,它繼承自 DbMigration。打開文件,在它的Up方法中,你會看到升級結構的代碼:
代碼清單2:升級數據庫結構的Up方法
public override void Up() { AlterColumn("dbo.Movies", "Title", c => c.String(nullable: false, maxLength: 60)); AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false)); AlterColumn("dbo.Movies", "Rating", c => c.String(nullable: false, maxLength: 5)); }
從代碼中可以看出,Title、Genre和Rating三個字段不再允許為空(這意味着你必須輸入一個值)。Rating 字段的最大長度為5,Title 的最大長度為60,最小長度為3。
Code First 確保在保存到數據庫的時候使用你指定的規則對數據進行驗證,例如,下面的代碼在調用SaveChanges的時候會拋出一個錯誤:
MovieDBContext db = new MovieDBContext(); Movie movie = new Movie(); movie.Title = "Gone with the Wind"; db.Movies.Add(movie); db.SaveChanges(); // <= 會引發一個服務器段的錯誤,因為movie的必須的字段沒有賦值
驗證規則在保存的時候自動生效使得程序變得更為健壯,它可以在是你忘記去驗證,而在不經意間阻止不合法的進入數據庫。
ASP.NET MVC 客戶端驗證
運行應用程序,瀏覽地址 /movies,點擊“Create New”鏈接添加一個電影。如果我們在輸入過程中出現一些不合法的數據,客戶端將會顯示一些錯誤,這是通過 jQuery 客戶端驗證來實現的。下面是一些錯誤信息:
圖1:客戶端驗證信息
當出現錯誤的時候,文本框會被加上紅色的邊框,並且會顯示一段錯誤描述信息。這些錯誤信息可以在客戶端(使用Javascript 和 jQuery)和服務器(當客戶端Javascript無效時)段生效。
一個真正的好處是,你不需要在MoviesController 或 Create.cshtml 中修改一行代碼來啟用客戶端驗證,控制器和視圖會根據我們之前定義在Movie類中的驗證特性自動選擇驗證規則。
表單數據出現錯誤的時候不會被提交到服務器端。
驗證是如何工作的
你可能會覺得奇怪,客戶端驗證是如何在沒有修改控制器或視圖代碼的情況下生成的。下面的代碼顯示了MovieController的Create方法,它和我們前面的教程中的Create代碼一樣,並沒有經過修改:
代碼清單3:Create 方法
// // GET: /Movies/Create public ActionResult Create() { return View(); } // // POST: /Movies/Create [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create(Movie movie) { if (ModelState.IsValid) { db.Movies.Add(movie); db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
第一個Create方法顯示一個表單,第二個Create方法用來處理POST請求提交的表單數據。第二個Create方法調用ModelState.IsValid來檢查movie數據是否存在驗證錯誤,調用這個方法來檢查驗證規則,如果存在錯誤,Create 方法將會重新顯示這個表單,如果沒有,則會將Movie數據保存到數據庫。在我們的例子中,當驗證出現錯誤的時候表單不會提交到服務器,第二個Create方法將不會調用。如果你禁用了Javascript客戶端驗證,第二個Create方法則會調用ModelState.IsValid對數據進行檢查。
你可以通過在HttpPost Create 方法中添加斷點來監視是否被調用。當客戶端出現錯誤的時候表單將不會提交,如果我們禁用客戶端的Javascript,表單將錯誤的數據提交到服務器,斷點將會跟蹤到。下面我們介紹一下如何在IE和Google瀏覽器中禁用Javascript。
在 IE 中禁用Javascript
打開Internet選項,在安全選項中選中“本地Intranet”,點擊“自定義級別”按鈕:
圖2:自定義安全級別
然后在安全設置窗口中,找到“活動腳本”,選擇“禁用”:
圖3:禁用活動腳本
點擊“確定”按鈕,然后跟蹤你提交的數據:
圖4:跟蹤到未通過驗證的數據
在火狐(FireFox)中禁用Javascript
圖5:在火狐中禁用Javascript
在Google Chrome中禁用Javascript
圖6:在Google Chrome 中禁用Javascript
下面是 Create.cshtml 視圖的代碼,它被控制器中的Create方法用來顯示初始的form表單,或在發生錯誤時重新顯示帶錯誤信息的表單數據。
代碼清單4:Create.cshtml
@model MvcMovie.Models.Movie @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) <fieldset class="form-horizontal"> <legend>Movie</legend> <div class="control-group"> @Html.LabelFor(model => model.Title, new { @class = "control-label" }) <div class="controls"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title, null, new { @class = "help-inline" }) </div> </div> <div class="control-group"> @Html.LabelFor(model => model.ReleaseDate, new { @class = "control-label" }) <div class="controls"> @Html.EditorFor(model => model.ReleaseDate) @Html.ValidationMessageFor(model => model.ReleaseDate, null, new { @class = "help-inline" }) </div> </div> <div class="control-group"> @Html.LabelFor(model => model.Genre, new { @class = "control-label" }) <div class="controls"> @Html.EditorFor(model => model.Genre) @Html.ValidationMessageFor(model => model.Genre, null, new { @class = "help-inline" }) </div> </div> <div class="control-group"> @Html.LabelFor(model => model.Price, new { @class = "control-label" }) <div class="controls"> @Html.EditorFor(model => model.Price) @Html.ValidationMessageFor(model => model.Price, null, new { @class = "help-inline" }) </div> </div> <div class="control-group"> @Html.LabelFor(model => model.Rating, new { @class = "control-label" }) <div class="controls"> @Html.EditorFor(model => model.Rating) @Html.ValidationMessageFor(model => model.Rating, null, new { @class = "help-inline" }) </div> </div> <div class="form-actions no-color"> <input type="submit" value="Create" class="btn" /> </div> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
模型格式化輸出
打開文件Movie.cs,檢查Movie類,System.ComponentModel.DataAnnotations 命名空間除了一套內置的驗證特性外,還提供了格式化特性。我們已經在ReleaseDate 和Price字段用到過DataType枚舉,下面的代碼展示了ReleaseDate和Price屬性中使用的DisplayFormat特性:
代碼清單5:使用了DisplayFormat的字段
[Display(Name = "Release Date")] [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } [Range(1, 100)] [DataType(DataType.Currency)] public decimal Price { get; set; }
DataType特性不是驗證特性,他們用來告訴試圖引擎如何繪制HTML。在上面的例子中,DataType.Date 特性使ReleaseDate顯示的時候只顯示日期部分,而不顯示時間。下面的DataType特性不驗證數據的格式:
[DataType(DataType.EmailAddress)] [DataType(DataType.PhoneNumber)] [DataType(DataType.Url)]
這些特性只為試圖引擎格式化顯示數據時提供建議。你可以使用RegularExpression 特性連驗證數據的格式。
除了使用現成的DataType 格式化特性之外,你還可以明確指定 DataFormatString 值。下面的代碼展示了ReleaseDate屬性使用格式化字符串的情況,你可以使用它來不顯示ReleaseDate日期的時間部分:
[DisplayFormat(DataFormatString = "{0:d}")] public DateTime ReleaseDate { get; set; }
下面的代碼將Price顯示為貨幣的格式:
[DisplayFormat(DataFormatString = "{0:c}")] public decimal Price { get; set; }
完整的Movie類代碼如下:
代碼清單6:Movie類
public class Movie { public int ID { get; set; } [Required] [StringLength(60, MinimumLength = 3)] public string Title { get; set; } [Display(Name = "Release Date")] [DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } [Required] public string Genre { get; set; } [Range(1, 100)] [DataType(DataType.Currency)] public decimal Price { get; set; } [StringLength(5)] [Required] public string Rating { get; set; } }
下面的代碼展示了如何將特性合並在一行顯示:
代碼清單7:合並特性后的Movie類
public class Movie { public int ID { get; set; } [Required, StringLength(60, MinimumLength = 3)] public string Title { get; set; } [Display(Name = "Release Date"), DataType(DataType.Date)] public DateTime ReleaseDate { get; set; } [Required] public string Genre { get; set; } [Range(1, 100), DataType(DataType.Currency)] public decimal Price { get; set; } [Required, StringLength(5)] public string Rating { get; set; } }
在本系列的下一部分,我們將回顧整個應用程序,並對自動生成的Details 和Delete 方法做一些改進。
本文同時發布在起飛網,原文地址:http://www.qeefee.com/mvc/mvc-5-adding-validation