在這節課程中,你將查看為影片控制器生成的方法和視圖。
運行程序,在瀏覽器中訪問/Movies。鼠標懸停在影片列表某條記錄的Edit鏈接上方,會看到鏈接類似於http://localhost:5279/Movies/Edit/1。
Edit的鏈接是由Views\Movies\Index.cshtml文件中的Html.ActionLink方法生成的,如下所示:@Html.ActionLink("Edit", "Edit", new { id=item.ID })
Html對象是System.Web.Mvc.WebViewPage基類暴露出來的一個屬性,作為助手來使用。助手的ActionLink方法令動態生成與控制器中的方法關聯的HTML超鏈接變得容易。ActionLink的第一個參數是顯示的文本(例如,<a>編輯</a>)。第二個參數是要調用的方法名。最后一個參數是生成的匿名路由數據對象(在這個例子中,是指值為1的ID)。
在上面生成的鏈接地址是http://localhost:5279/Movies/Edit/1。默認路由(在App_Start\RouteConfig.cs中創建)解析URL的模式為{controller}/{action}/{id}。因此,ASP.NET將http://localhost:5279/Movies/Edit/1轉換成Movies控制器的Edit方法的請求,並攜帶一個值為1參數ID。在App_Start\RouteConfig.cs文件中查看以下代碼:
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } }
你也可以使用查詢字符串來傳遞方法參數。例如,http://localhost:5279/Movies/Edit?ID=1同樣傳遞值為1的ID參數給Movies控制器的Edit方法。
打開Movies控制器文件。兩個Edit方法如下所示:
// // GET: /Movies/Edit/5 public ActionResult Edit(int id = 0) { Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } // // POST: /Movies/Edit/5 [HttpPost] public ActionResult Edit(Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
注意第二個Edit方法前面加了HttpPost屬性。該屬性指定這個重載的Edit方法僅在接受Post請求時被調用。你可以將HttpGet屬性應用在第一個Edit方法,但那不是必須的,因為它是默認的。(我們將為HttpGet方法隱性地指定HttpGet屬性)。
HttpGet屬性的Edit方法獲取影片ID參數,使用Entity Framework的Find方法查找影片,並返回選中的影片給Edit視圖。當Edit方法被調用時沒有參數傳入時,ID參數指定0作為默認值。當無法找到影片時,返回HttpNotFound。當腳手架系統創建Edit視圖時,查看Movie類並為該類的每個屬性創建<label>和<input>元素。下面的例子展示了生成的Edit視圖:
@model MvcMovie.Models.Movie @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Movie</legend> @Html.HiddenFor(model => model.ID) <div class="editor-label"> @Html.LabelFor(model => model.Name) </div> <div class="editor-field"> @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name) </div> <div class="editor-label"> @Html.LabelFor(model => model.Genra) </div> <div class="editor-field"> @Html.EditorFor(model => model.Genra) @Html.ValidationMessageFor(model => model.Genra) </div> <div class="editor-label"> @Html.LabelFor(model => model.Price) </div> <div class="editor-field"> @Html.EditorFor(model => model.Price) @Html.ValidationMessageFor(model => model.Price) </div> <div class="editor-label"> @Html.LabelFor(model => model.Date) </div> <div class="editor-field"> @Html.EditorFor(model => model.Date) @Html.ValidationMessageFor(model => model.Date) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
注意該視圖模板在文件頂部有@model MvcMovie.Models.Movie語句--指定了視圖期望的模型是Movie類型。
腳手架代碼使用幾個Helper方法來生成流式的Html標記。Html.LabelFor顯示字段名稱(片名、價格、風格等)。Html.EditorFor生成<input>元素。Html.ValidationMessageFor展示與屬性關聯的驗證信息。
運行程序,導航到/Movies 地址。點擊Edit超鏈接。在瀏覽器中查看頁面源代碼。表單元素的Html源碼如下所示:
<!DOCTYPE html> <html lang="zh"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta charset="utf-8" /> <title>Edit - 電影應用程序</title> <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" /> <meta name="viewport" content="width=device-width" /> <link href="/Content/site.css" rel="stylesheet"/> <script src="/Scripts/modernizr-2.5.3.js"></script> </head> <body> <header> <div class="content-wrapper"> <div class="float-left"> <p class="site-title"><a href="/">MVC 電影</a></p> </div> <div class="float-right"> <section id="login"> <ul> <li><a href="/Account/Register" id="registerLink">注冊</a></li> <li><a href="/Account/Login" id="loginLink">登錄</a></li> </ul> </section> <nav> <ul id="menu"> <li><a href="/">主頁</a></li> <li><a href="/Home/About">關於</a></li> <li><a href="/Home/Contact">聯系方式</a></li> </ul> </nav> </div> </div> </header> <div id="body"> <section class="content-wrapper main-content clear-fix"> <h2>Edit</h2> <form action="/Movies/Edit/1" method="post"> <fieldset> <legend>Movie</legend> <input data-val="true" data-val-number="字段 ID 必須是一個數字。" data-val-required="ID 字段是必需的。" id="ID" name="ID" type="hidden" value="1" /> <div class="editor-label"> <label for="Name">Name</label> </div> <div class="editor-field"> <input class="text-box single-line" id="Name" name="Name" type="text" value="少年派的奇幻之旅" /> <span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="Genra">Genra</label> </div> <div class="editor-field"> <input class="text-box single-line" id="Genra" name="Genra" type="text" value="冒險" /> <span class="field-validation-valid" data-valmsg-for="Genra" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="Price">Price</label> </div> <div class="editor-field"> <input class="text-box single-line" data-val="true" data-val-number="字段 Price 必須是一個數字。" data-val-required="Price 字段是必需的。" id="Price" name="Price" type="text" value="60.96" /> <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="Date">Date</label> </div> <div class="editor-field"> <input class="text-box single-line" data-val="true" data-val-date="字段 Date 必須是日期。" data-val-required="Date 字段是必需的。" id="Date" name="Date" type="datetime" value="2012/12/5 0:00:00" /> <span class="field-validation-valid" data-valmsg-for="Date" data-valmsg-replace="true"></span> </div> <p> <input type="submit" value="Save" /> </p> </fieldset> </form> <div> <a href="/Movies">Back to List</a> </div> </section> </div> <footer> <div class="content-wrapper"> <div class="float-left"> <p>© 2012 - 我的 ASP.NET MVC 應用程序</p> </div> </div> </footer> <script src="/Scripts/jquery-1.7.1.js"></script> <script src="/Scripts/jquery.unobtrusive-ajax.js"></script> <script src="/Scripts/jquery.validate.js"></script> <script src="/Scripts/jquery.validate.unobtrusive.js"></script> </body> </html>
包含<input>元素的HTML <form> 元素的action屬性設置為/Movies/Edit ,方法為post。點擊Edit按鈕,表單數據將被post到服務器。
處理Post請求
下面列表顯示了處理HttpPost請求版本的Edit方法
// // POST: /Movies/Edit/5 [HttpPost] 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模型綁定機制獲取post表單值,創建Movie對象作為參數。ModelState.IsValid方法驗證表單提交的數據可以用來修改(編輯或更新)Movie對象。如果數據有效,則影片數據將被保存到MovieDbContext實例集合中。新的影片數據在調用MovieDbContext的SaveChanges時保存到數據庫。保存完數據后,代碼引導用戶到MoviesController 的Index方法,在那展示包括剛剛修改的影片在內的影片集合。
如果post的數據無效,將在表單中重新顯示。Edit.cshtml視圖模板中的Html.ValidationMessageFor助手負責顯示錯誤信息。
譯者注:原文在該部分有大量篇幅提示在非英語母語國家,使用逗號來替代貨幣中的小數點,來實現JQuery正確驗證數據的目的,與主題無關,在此做刪節處理,有興趣的可以閱讀英文原文。
所有的HttpGet方法遵循相似的模式。獲取一個movie對象(或者對象集合,比如在Index例子中),從模型傳遞到視圖。Create方法傳遞空對象給Create視圖。創建、編輯、刪除或者修改數據等所有操作放在HttpPost重載方法中。在HttpGet方法中修改數據存在安全隱患,詳細信息請查看ASP.NET MVC Tip #46 – Don’t use Delete Links because they create Security Holes。在Get方法中修改數據同樣違法Http最佳實踐以及Rest模式(指定Get請求不應當變更你的應用程序狀態)。換句話說,執行Get操作應該是一個不影響以及不會修改此前數據的安全操作。
本教程所有文章導航
本系列共10篇文章,翻譯自Asp.Net MVC4 官方教程,由於本系列文章言簡意賅,篇幅適中,從一個示例開始講解,全文最終完成了一個管理影片的小系統,非常適合新手入門Asp.Net MVC4,並由此開始開發工作。
原文供9篇文章,譯者將其中第6篇拆成了2篇
1. Asp.Net MVC4 入門介紹
· 原文地址:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/intro-to-aspnet-mvc-4
· 譯文地址:http://www.cnblogs.com/seawaving/archive/2012/12/03/2800210.html
2. 添加一個控制器
· 原文地址:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-controller
· 譯文地址:http://www.cnblogs.com/seawaving/archive/2012/12/04/2801949.html
3. 添加一個視圖
· 原文地址:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-view
· 譯文地址:http://www.cnblogs.com/seawaving/archive/2012/12/04/2801988.html
4. 添加一個模型
· 原文地址:http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/adding-a-model
· 譯文地址:http://www.cnblogs.com/seawaving/archive/2012/12/05/2803012.html
5. 從控制器訪問數據模型
· 譯文地址:http://www.cnblogs.com/seawaving/archive/2012/12/05/2803429.html
6. 查看Edit方法和Edit視圖
· 譯文地址:http://www.cnblogs.com/seawaving/archive/2012/12/05/2804100.html
http://www.cnblogs.com/seawaving/archive/2012/12/06/2804590.html
7. 為Movie模型和庫表添加字段
· 譯文地址:http://www.cnblogs.com/seawaving/archive/2012/12/06/2805401.html
8. 為模型添加驗證
· 譯文地址:http://www.cnblogs.com/seawaving/archive/2012/12/06/2806322.html
9. 查看Detail和Delete方法
· 譯文地址:http://www.cnblogs.com/seawaving/archive/2012/12/10/2811064.html