ASP.NET MVC 5 學習教程:Edit方法和Edit視圖詳解


起飛網 ASP.NET MVC 5 學習教程目錄:

在本節中,我們繼續研究生成的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鏈接地址

image

Edit 鏈接是通過Html.ActionLink 方法生成的,在Views\Movies\Index.cshtml 視圖中,代碼如下:

代碼清單2:Html.ActionLink 方法

@Html.ActionLink("Edit", "Edit", new { id=item.ID })

圖2:Html.ActionLink 方法介紹

image

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:通過查詢字符串傳遞參數

image

打開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 列表中(dbMovieDBContext 的實例),通過調用 db.SaveChanges 方法將修改后的電影數據保存在數據庫中。在數據保存之后,RedirectToAction 將跳轉到 Index 方法,用來顯示電影列表,此時就能看到更新后的電影信息。

在用戶輸入過程中,一旦輸入了未通過驗證的值,客戶端就會顯示一個錯誤信息,這些功能是通過Javascript 完成的,如果你禁用了Javascript,客戶端驗證功能將會失效,但服務器會檢查到不合法的數據,然后將包含錯誤信息的表單重新顯示在客戶端。在后面的章節中我們將介紹更多驗證的細節。

Edit.cshtml 視圖中的 Html.ValidationMessageFor 方法會顯示相應的錯誤信息。如下圖:

圖4:編輯Movie時的驗證信息

image_thumb

所有處理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 菜單

image

在左側單擊“聯機”,在查詢框中輸入“Globalize”:

圖6:查詢 Globalize 安裝包

image

點擊“安裝”按鈕,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


免責聲明!

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



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