起飛網 ASP.NET MVC 5 學習教程目錄:
- 添加控制器
- 添加視圖
- 修改視圖和布局頁
- 控制器傳遞數據給視圖
- 添加模型
- 創建連接字符串
- 通過控制器訪問模型的數據
- 生成的代碼詳解
- 使用 SQL Server LocalDB
- Edit方法和Edit視圖詳解
- 添加查詢
- Entity Framework 數據遷移之添加字段
- 添加驗證
- Details 和 Delete 方法詳解
在本節中,我們繼續研究生成的Edit方法和視圖。但在研究之前,我們先將 release date 弄得好看一點。打開 Models\Movie.cs 文件,添加下面黃色背景的行:
代碼清單1:Models\Movie.cs 文件
using System; using System.ComponentModel.DataAnnotations; using System.Data.Entity; namespace MvcMovie.Models { public class Movie { public int ID { get; set; } public string Title { get; set; } [
Display(Name = "Release Date")] [DataType(DataType
.Date)] public DateTime ReleaseDate { get; set; } public string Genre { get; set; } public decimal Price { get; set; } } public class MovieDBContext : DbContext { public DbSet<Movie> Movies { get; set; } } }
我們將在下一節中介紹 DataAnnotations。Display 特性指定了顯示的字段名(本例中“Release Date”替換了“ReleaseDate”)。DataType 特性指定了數據類型,在本例中它是日期類型,因此存儲在該字段的時間信息將不會顯示出來。
運行應用程序,在瀏覽器地址欄中追加/movies 來訪問 Movies 控制器。將鼠標放在Edit 鏈接上面,查看它鏈接到的地址:
圖1:查看Edit鏈接地址
Edit 鏈接是通過Html.ActionLink 方法生成的,在Views\Movies\Index.cshtml 視圖中,代碼如下:
代碼清單2:Html.ActionLink 方法
@Html.ActionLink("Edit", "Edit", new { id=item.ID })
圖2:Html.ActionLink 方法介紹
Html 對象是System.Web.Mvc.WebViewPage 基類中的一個屬性,ActionLink 方法使動態生成 控制器中方法的 HTML 超鏈接更為簡單。ActionLink 方法的第一個參數是要顯示的鏈接文字(例如<a>Edit Me</a>
);第二個參數是要調用的控制器方法(在這里是 Edit 方法);最后一個參數是生成路由數據用的匿名對象(在這里是id,值為1)。
在圖1中顯示的生成地址是http://localhost:2264/Movies/Edit/1 。默認的路由匹配 {controller}/{action}/{id}
URL模式 。因此,ASP.NET 將請求地址http://localhost:2264/Movies/Edit/1 翻譯為MoviesController 的Edit 方法,參數id為1。查看App_Start\RouteConfig.cs 文件中的代碼:
代碼清單3:默認路由規則
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
你還可以使用查詢字符串傳遞參數,例如 http://localhost:xxxxx/Movies/Edit?ID=1 也可以將參數id為1的值傳遞給Movies控制器。
圖3:通過查詢字符串傳遞參數
打開Movies控制器,它包含了兩個Edit 方法,代碼如下:
代碼清單4:兩個Edit方法 - MoviesController.cs
// // GET: /Movies/Edit/5 public ActionResult Edit(Int32 id) { Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } // // POST: /Movies/Edit/5
[HttpPost
] [ValidateAntiForgeryToken] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
注意第二個 Edit 方法,它被HttpPost特性修飾(代碼中黃色背景標注),這個特性指定只有POST請求才能調用這個重載的Edit方法。我們可以為第一個Edit方法添加HttpGet特性,但這不是必須的,因為它是默認值(我們將未標記的方法認定為HttpGet方法)。第二個Edit 方法還有一個 ValidateAntiForgeryToken 特性,這個特性用來阻止偽造的請求,它和視圖(Views\Movies\Edit.cshtml)中的 @Html.AntiForgeryToken() 是成對出現的。
代碼清單5:@Html.AntiForgeryToken() 用法
@model MvcMovie.Models.Movie @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) <fieldset class="form-horizontal"> <legend>Movie</legend> @Html.HiddenFor(model => model.ID) <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>
@Html.AntiForgeryToken() 生成一個表單防偽標記,必須與 MoviesController 中的 Edit 方法匹配。
HttpGet標記的Edit方法接收一個ID的參數,通過Entity Framework Find方法查找電影,並將找到的結果返回個Edit 視圖。如果調用Edit方法的時候沒有參數,ID參數的值將會是默認的0。如果未找到電影信息,控制器將返回一個HttpNotFound。當支架系統創建Edit 視圖的時候,它會檢查Movie類,為它的每一個屬性創建繪制<label>
和<input>
元素的代碼。下面的示例展示了Visual Studio 支架系統創建的Edit視圖代碼:
代碼清單6:Edit 視圖
@model MvcMovie.Models.Movie @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) <fieldset class="form-horizontal"> <legend>Movie</legend> @Html.HiddenFor(model => model.ID) <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="form-actions no-color"> <input type="submit" value="Save" class="btn" /> </div> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
在視圖文件頂部的語句 @model MvcMovie.Models.Movie 指明該視圖需要一個 Movie 型的模型。
支架生成的代碼使用了很多精簡HTML標記的幫助方法,Html.LabelFor 方法用來顯示字段名( "Title", "ReleaseDate", "Genre", 和 "Price"),Html.EditorFor 方法生成一個HTML <input> 元素,Html.ValidationMessageFor 方法結合屬性顯示一些驗證信息。
運行應用程序,導航到 /movies 地址,點擊 Edit 鏈接,在瀏覽器中,查看頁面源代碼,form標簽的HTML代碼如下:
代碼清單7:生成的form標簽HTML代碼
<form action="/Movies/Edit/1" method="post"> <
input name="__RequestVerificationToken" type="hidden" value="vM6-yBtYJY5uRgKm3ivFw9gLMjauE9i2-Wi6Y--2Swm4-BlucfrG71zQV3n773tT9i8ytaG5WSanfBBd54qIhAKAkTJO_Z0UhRaGPDhMJ9M1" /> <fieldset class
="form-horizontal"> <legend>Movie</legend> <input data-val="true" data-val-number="The field ID must be a number." data-val-required="ID 字段是必需的。" id="ID" name="ID" type="hidden" value="1" /> <div class="control-group"> <label class="control-label" for="Title">Title</label> <div class="controls"> <input class="text-box single-line" id="Title" name="Title" type="text" value="中國合伙人" /> <span class="field-validation-valid help-inline" data-valmsg-for="Title" data-valmsg-replace="true"></span> </div> </div> <div class="control-group"> <label class="control-label" for="ReleaseDate">Release Date</label> <div class="controls"> <input class="text-box single-line" data-val="true" data-val-date="The field Release Date must be a date." data-val-required="Release Date 字段是必需的。" id="ReleaseDate" name="ReleaseDate" type="date" value="2013/6/18" /> <span class="field-validation-valid help-inline" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span> </div> </div> <div class="control-group"> <label class="control-label" for="Genre">Genre</label> <div class="controls"> <input class="text-box single-line" id="Genre" name="Genre" type="text" value="勵志" /> <span class="field-validation-valid help-inline" data-valmsg-for="Genre" data-valmsg-replace="true"></span> </div> </div> <div class="control-group"> <label class="control-label" for="Price">Price</label> <div class="controls"> <input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="Price 字段是必需的。" id="Price" name="Price" type="text" value="70.00" /> <span class="field-validation-valid help-inline" data-valmsg-for="Price" data-valmsg-replace="true"></span> </div> </div> <div class="form-actions no-color"> <input type="submit" value="Save" class="btn" /> </div> </fieldset> </form>
看一下這個form標簽,它的action屬性是/movies/edit/1,說明form將提交到這個地址,而它里面包含的<input>標簽則對應每一個Movie類的字段。當點擊“Save”按鈕時,form中的數據將提交到服務器。第二行代碼中,我使用高亮提示,這行代碼是使用@Html.AntiForgeryToken() 生成的隱藏域,用來阻止偽造的請求。
處理POST請求
下面是接收POST請求的Edit方法:
代碼清單8:Edit 方法
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
ASP.NET MVC model binder 使用提交的表單數據創建一個 Movie 對象,作為 movie 參數傳遞給 Edit 方法。ModelState.IsValid 驗證 form 提交的數據是否能夠用來修改(編輯或更新)Movie對象,如果驗證通過,電影數據就會保存在 db.Movies 列表中(db 是 MovieDBContext 的實例),通過調用 db.SaveChanges 方法將修改后的電影數據保存在數據庫中。在數據保存之后,RedirectToAction 將跳轉到 Index 方法,用來顯示電影列表,此時就能看到更新后的電影信息。
在用戶輸入過程中,一旦輸入了未通過驗證的值,客戶端就會顯示一個錯誤信息,這些功能是通過Javascript 完成的,如果你禁用了Javascript,客戶端驗證功能將會失效,但服務器會檢查到不合法的數據,然后將包含錯誤信息的表單重新顯示在客戶端。在后面的章節中我們將介紹更多驗證的細節。
Edit.cshtml 視圖中的 Html.ValidationMessageFor 方法會顯示相應的錯誤信息。如下圖:
圖4:編輯Movie時的驗證信息
所有處理Get請求的方法都有相似的模式:他們獲取一個電影對象(在Index中是電影列表),然后傳遞給View。Create 方法傳遞一個空的電影數據給視圖。使用HTTP GET 方法修改數據存在安全風險,也同樣違背了HTTP最佳實踐,並且 REST 模式中明確指出,GET 請求不應該改變應用程序的狀態,換句話說,GET 操作應該是一個安全的操作,沒有副作用,也不會修改你的持久化數據。
本地化驗證
如果你是用英語,這部分可以跳過。作為漢語國家用戶,我還是把這部分翻譯一下吧。
對於非英語地區的用戶來說,小數點使用逗號(","),還有非美語的日期格式,為了支持Jquery 驗證,你必須包含 globalize.js 和特定的 cultures/globalize.cultures.js 文件,在Javascript中使用 Globalize.parseFloat。你可以通過NuGet獲得 jQuery non-English validation (英語地區不要安裝Globalize)。
From the Tools menu click Library Package Manager, and then click Manage NuGet Packages for Solution.
在菜單欄中單擊“工具”>“庫程序包管理器”>“管理解決方案的 NuGet程序包”。
圖5:NuGet 菜單
在左側單擊“聯機”,在查詢框中輸入“Globalize”:
圖6:查詢 Globalize 安裝包
點擊“安裝”按鈕,Scripts\jquery.globalize\globalize.js 文件將會添加到項目中,文件夾 Scripts\jquery.globalize\cultures\ 中包含了很多Javascript文件。
下面的代碼顯示了將文件 Views\Movies\Edit.cshtml 使用漢語區域所作的修改(原文作者使用法語作為演示):
代碼清單9:script 代碼 - Edit.cshtml
@section Scripts { @Scripts.Render("~/bundles/jqueryval") <script src="~/Scripts/jquery.globalize/globalize.js"></script> <script src="~/Scripts/jquery.globalize/cultures/globalize.culture.zh-CN.js"></script> <script> $.validator.methods.number = function (value, element) { return this.optional(element) || !isNaN(Globalize.parseFloat(value)); } $(document).ready(function () { Globalize.culture('zh-CN'); }); </script> <script> jQuery.extend(jQuery.validator.methods, { range: function (value, element, param) { //Use the Globalization plugin to parse the value var val = $.global.parseFloat(value); return this.optional(element) || ( val >= param[0] && val <= param[1]); } }); </script> <script> $.validator.methods.date = function (value, element) { return this.optional(element) || !isDate(Globalize.parseDate(value)); } </script> }
為了避免在每個編輯視圖都寫上這么一大段代碼,你可以將他們寫在布局頁。
在下一節中我們將為程序實現查找功能。
本文同時發布在起飛網,原文地址:http://www.qeefee.com/mvc/mvc-5-examining-the-edit-methods-and-edit-view