ASP.NET MVC學習筆記06編輯方法和編輯檢視
上一篇中,說到了MVC生成的Index方法,和Details方法,現在來說一下自動生成的方法和檢視,應該怎麼的來進行編輯。
優化日期顯示
在這之前,先對前面的程式碼進行優化,使得釋出日期屬性(ReleaseDate
)看上去更好。開啟Models/Movies.cs
參考下圖進行修改。
上圖中用到了DataAnnotations
。Display屬性指明要顯示的欄位的名 稱(在本例中“Release Date”來代替“ReleaseDate”)。DataType屬性用於指定型別的資料,在本例它是一個日期,所以不會顯示存放在該欄位時間詳情。DisplayFormat屬性在Chrome瀏覽器裡有一個bug:呈現的日期格式不正確。
除錯,瀏覽,然後點選一個條目,進入編輯。
如上圖所示,Edit(編輯)連結是由Views MoviesIndex.cshtml
檢視中Html.ActionLink
方法所生成的.
@Html.ActionLink("Edit", "Edit", new { id=item.ID })
Html物件是一個 Helper, 以屬性的形式在System.Web.Mvc.WebViewPage
基類上公開。ActionLink
是一個幫助方法(Helper),便於動態生成指向Controller中操作方法 的HTML 超連結連結。ActionLink
方法的第一個引數是想要呈現的連結文字 (例如,<a>Edit Me</a>
因此跳轉的連結為,http://localhost:50948/movies/Edit/1
,預設的路由 (在
App_StartRouteConfig.cs
中設定)使用的 URL 匹配模式為: {controller}/{action}/{id}
。因 此,ASP.NET 將 http://localhost:xxxxx/Movies/Edit/4
轉化到 Movies 控制器中 Edit操作 方法,引數 ID等於1 的請求。所以,輸入http://localhost:50948/movies/Edit?id=1
控制器的Edit方法
再來看看MoviesController中的Edit的兩個方法。
注意,第二個Edit操作方法的上面有HttpPost
屬性。此屬性指定了Edit方法的過載,此方法僅 被POST 請求所呼叫。可以將HttpGet
屬性應用於第一個編輯方法,但不需要這樣,因為它是預設的屬性。(操作方法會被隱式的指定為HttpGet
屬性,從而作為 HttpGet
方法。) 繫結(Bind)屬性是另一個重要安全機制,可以防止黑客攻擊(從over-posting資料到模型)。應該只包含在bind屬性屬性,本教程中使用的簡單模型,模型中繫結所有資料。ValidateAntiForgeryToken
屬性是用來防止偽造的請求,並配對@Html.AntiForgeryToken()
檔案 ( ViewsMoviesEdit.cshtml
),如下圖所示,部分在Edit View
檔案:
@Html.AntiForgeryToken() 生成隱藏的窗體, 防偽令牌必須匹配Movies控制器的 Edit 方法。在教程 XSRF/CSRF Prevention in MVC,你可以讀到更多關於跨站點請求偽造 (也稱為XSRF或CSRF)。
HttpGet Edit
方法會獲取電影ID引數、 查詢影片使用 Entity Framework 的Find 方法,並返回 到選定影片的編輯檢視。如果不帶引數呼叫Edit 方法,ID 引數被指定為預設值 零。如果找不到一 部電影,則返回 HttpNotFound 。當 scaffolding自動建立編輯檢視時,它會檢視Movie類併為 類的每個屬性建立用於 Render的<label>
和<input>
的元素。
注意,檢視模板在檔案的頂部有 @model MvcMovie.Models.Movie
的宣告,這將指定視 圖期望的模型型別為` Movie。
scaffolded
自動生成的程式碼,使用了Helper 方法的幾種簡化的 HTML 標記 。Html.LabelFor
用來顯示欄位的名稱(”Title”、”ReleaseDate”、”Genre”或”Price”)。Html.EditorFor
用來呈現 HTML <input>
元素。Html.ValidationMessageFor
用來 顯示與該屬性相關聯的任何驗證訊息。檢視模板在檔案的頂部有 @model MvcMovie.Models.Movie
的宣告,這將指定視 圖期望的模型型別為 Movie。
處理 POST 請求
回看前面的Eidt的Post方法。
ASP.NET MVC model binder
接收form所post的資料,並轉換所接收的 Movie請求資料從而建立一個Movie物件。ModelState.IsValid
方法用於驗證提交的表單資料是否可用於修改(編輯或更新)一個Movie物件。如果資料是有效的電影資料,將儲存到資料庫的Movies集合(MovieDBContext
例項)。通過呼叫MovieDBContext的SaveChanges
方法,新的電影資料會被儲存到資料庫。資料儲存之後,程式碼會把使用者重定向到 MoviesController
類的Index操作方法,頁面將顯示電影列表,同時包括剛剛所做的更新。
一旦客戶端驗證確定某個欄位的值是無效的,將顯示出現錯誤訊息。如果禁用 JavaScript,則不會有客戶端驗證,但伺服器將檢測回傳的值是無效的,而且將重新顯示 表單中的值與錯誤訊息。在本教程的後面,我們驗證更詳細的審查。 Edit.cshtml
檢視模板 中的 Html.ValidationMessageFor Helper
將用來顯示相應的錯誤訊息。
所有 HttpGet方法遵循類似的模式。他們得到一個電影物件(或物件列表中,如本案例的 Index),並把模型資料傳遞給檢視。Create方法傳遞一個空的影片物件給Create檢視。 所有的 create, edit, delete方法,或其他的方法: 用HttpPost
過載的方法修改資料。修改 資料在HTTP GET
方法, 存在安全風險。在HTTP GET
方法中修改資料也違反HTTP 的最佳實踐和REST模式架構,指明GET請求不應該改變你的應用程式的狀態。換句話說,執行GET操作應該是一個安全,操作,無任何副作用,不會修改你的持久化資料。
按照電影流派新增搜尋
首先,如果之前添加了 HttpPost
的Index方法,請立即刪除它。
下面,通過一些列的修改,來讓使用者可以通過流派來搜尋電影。先從Controller中的index方法開始。
這個版本的 Index方法將接受一個附加的 movieGenre
引數。前幾行的程式碼會建立一個 List物件來儲存資料庫中的電影流派。
下面的程式碼是從資料庫中檢索所有流派的 LINQ 查詢:
var GenreQry = from d in db.Movies
orderby d.Genre
select d.Genre;
該程式碼使用泛型 List集合的 AddRange
方法將所有不同的流派,新增到集合中的。(使 用 Distinct
修飾符,不會新增重複的流派 – 例如,在我們的示例中添加了兩次喜劇)。
該程式碼然後在ViewBag
物件中儲存了流派的資料列表。的SelectList
物件在ViewBag作 為儲存類資料(這樣的電影流派),然後在下拉列表框中的資料訪問類別,是一個典型的MVC applications
的方法。
下面的程式碼演示如何檢查 movieGenre引數。如果它不是空的,程式碼進一步指定了所查詢的電影流派。
if (!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
如前所述,查詢資料不會在資料庫上執行,直到電影列表迭代結束(恰發生在View, Index方法返回後)。
注意:這個地方用到了LinQ的知識,如果對LinQ不太瞭解的,可以查閱官方文件.
Index檢視新增標記
在ViewsMoviesIndex.cshtml
檔案中,新增Html.DropDownList
輔助方法,在TextBox
前。完成的程式碼如下圖所示:
下面的程式碼:
@Html.DropDownList("movieGenre", "All")
ViewBag
中,”movieGenre
“ 參考作為key在DropDownList
中搜索 IEnumerable<SelectListItem >
.
ViewBag
填入的操作方法:
引數“All”提供的項列表中的預先選擇的。如我們使用下面的程式碼:
@Html.DropDownList("movieGenre", "Comedy")
在我們的資料庫中,我們擁有與“喜劇”流派的電影,“喜劇”在下拉列表中將預先選 擇。因為我們沒有一個電影流派“All”,也沒有“All”的 SelectList
,所以當我們post back後不做任何選擇,movieGenre
查詢字串值是空的。
執行應用程式並瀏覽 /Movies/Index
。嘗試搜尋流派,來檢索資訊。
在本篇中,建立了一個搜尋的方法和檢視,使用它,使用者可以通過電影標題和流派來搜 索。在下一篇中,將看到如何新增一個屬性到 Movie model,和如何新增一個初始值設定項值,它會自動建立一個測試資料庫。