學習ASP.NET MVC(六)——我的第一個ASP.NET MVC 編輯頁面

weixin_34391854發表於2014-07-27

      在上一文章中由Entity Framework(實體框架)去實現了對資料庫的CURD操作。在本篇文章中,主要是除錯修改自動生成的動作方法和檢視,以及除錯編輯功能與編輯功能的Book控制器。

      首先,在Visual Studio執行一下上次的應用程式,通過瀏覽器訪問http://localhost:36878/Book。將滑鼠指標移到瀏覽器中的一個“Edit”連結上,就可以看到這個“Edit”指向的URL如下圖紅框所示。

 

       “Edit” 連結通過Html.ActionLink方法在瀏覽中生成指向Views\Book\Edit.cshtml 檢視的連結。程式碼如下。

   

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

 

       如上圖中所示,這個“HTML”物件是通過System.Web.Mvc.WebViewPage基類的屬性暴露出來的。這個ActionLink方法可以很容易地動態生成一個連結,這個連結指向控制器的一個動作方法。ActionLink方法的第一個引數是顯示連結的文字資訊(例如,“Edit”)。第二個引數是指動作方法要呼叫控制器中的方法名稱。最後一個引數是生成的路由資料(如示例中的ID=8)的一個匿名物件。 

       在上圖中所示的生成的“Edit”連結是http://localhost:36878/Book/Edit/8。預設路由URL模板是{controller}/{action}/{id}(模板程式碼位於App_Start\ RouteConfig.cs)。因此,瀏覽器會發出http://localhost:36878/Book/Edit/8 這個URL請求,同時傳遞引數ID=8給Asp.net MVC的Book控制器的“Edit”方法。下面就是App_Start\ RouteConfig.cs裡面的路由模板設定。

 

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 }

    );

}

 

          您還可以使用action方法後面帶上查詢引數。例如,URL http://localhost:36878/Book/Edit?ID=8,通過ID=8,把引數ID的資料(8)傳遞給了Book控制器的“Edit”方法。以上兩種方式的執行結果如下圖。

 

         其次,我們開啟BookController.cs檔案,來仔細看看裡面的兩個“Edit”方法。程式碼如下所示。

 

//

// GET: /Book/Edit/8
 

        public ActionResult Edit(int id = 0)
        {

            Book book = db.Books.Find(id);

            if (book == null)

            {

                return HttpNotFound();

            }

            return View(book);

        }

//

// POST: /Book/Edit/8
 

        [HttpPost]
        public ActionResult Edit(Book book)
{
if (ModelState.IsValid) { db.Entry(book).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(book); }

 

      請注意,第二個“Edit”方法的上面有一個“HttpPost”屬性。這個屬性指定了此方法只能通過POST請求來呼叫。也可以給第一個方法上面加上“HTTPGET”屬性,但這不是必要的,因為HTTPGET屬性是預設的。 Visual Studio將會給所有沒有指明的方法,預設且隱性的分配HTTPGET屬性,這種隱性分配了“HTTPGET”屬性的方法稱為HTTPGET操作方法。) 
        第一個“HTTPGET”的“ Edit”方法是將書籍的ID做為引數,使用Entity Framework查詢方法找到指定ID的書籍,並返回找到的書籍資料給編輯檢視。 此方法中的ID引數被指定了預設值,如果當呼叫時不帶引數,則ID會使用預設值0。如果書籍記錄沒有找到,將會返回HttpNotFound由基架系統建立的編輯檢視通過<label><input>來呈現Book類中的每個屬性。示例程式碼如下。

 

@model MvcApplication1.Models.Book 

@{

    ViewBag.Title = "Edit";
}

<h2>Edit</h2>
 

@using (Html.BeginForm()) {

    @Html.ValidationSummary(true) 

    <fieldset>

        <legend>Book</legend> 

        @Html.HiddenFor(model => model.BookID) 

        <div class="editor-label">

            @Html.LabelFor(model => model.Category)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.Category)

            @Html.ValidationMessageFor(model => model.Category)

        </div> 

        <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.Numberofcopies)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.Numberofcopies)

            @Html.ValidationMessageFor(model => model.Numberofcopies)

        </div> 

        <div class="editor-label">

            @Html.LabelFor(model => model.AuthorID)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.AuthorID)

            @Html.ValidationMessageFor(model => model.AuthorID)

        </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.PublishDate)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.PublishDate)

            @Html.ValidationMessageFor(model => model.PublishDate)

        </div>

        <p>
            <input type="submit" value="Save" />

        </p>

    </fieldset>

}

<div>

    @Html.ActionLink("Back to List", "Index")

</div>

 

@section Scripts {

    @Scripts.Render("~/bundles/jqueryval")

}

 

       請注意,這個檢視模板檔案的頂部中有一句@model MvcApplication1.Models.Book,這一句程式碼的意思是在檔案中宣告瞭物件的型別定義 ——即指定了本檢視中的物件型別是Book。 
       由VS自動生成的基架程式碼中使用了幾個輔助方法,這幾個輔助方法用來減少輸入HTML標記。

    第一個輔助方法是:Html.LabelFor輔助方法用於顯示欄位的名稱(例如:“Name”,“PublishDate”,“Price)。

     第二個輔助方法是:Html.EditorFor輔助方法用於自動生成一個HTML<input>元素。

    第三個輔助方法是:Html.ValidationMessageFor輔助方法用於顯示與該屬性關聯的驗證訊息。 

 

      再次,按F5執行應用程式,並在瀏覽器中瀏覽/Book網址,在頁面中,使用滑鼠左鍵單擊“Edit”連結。瀏覽器會自動導航到編輯頁面,在頁面中,單擊滑鼠右鍵,在彈出選單中選擇“檢視原始碼”,你會看到已經生成的HTML表單元素。如下。

     

<form action="/book/Edit/8" method="post">    <fieldset>

        <legend>Book</legend>
 

        <input data-val="true" data-val-number="欄位 BookID 必須是一個數字。" data-val-required="BookID 欄位是必需的。" id="BookID" 
name
="BookID" type="hidden" value="8" /> <div class="editor-label"> <label for="Category">Category</label> </div> <div class="editor-field"> <input class="text-box single-line" id="Category" name="Category" type="text" value="SAP" /> <span class="field-validation-valid" data-valmsg-for="Category" data-valmsg-replace="true"></span> </div> <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="SAP" /> <span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="Numberofcopies">Numberofcopies</label> </div> <div class="editor-field"> <input class="text-box single-line" data-val="true" data-val-number="欄位 Numberofcopies 必須是一個數字。"
data-val-required
="Numberofcopies 欄位是必需的。" id="Numberofcopies" name="Numberofcopies" type="number" value="12" /> <span class="field-validation-valid" data-valmsg-for="Numberofcopies" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="AuthorID">AuthorID</label> </div> <div class="editor-field"> <input class="text-box single-line" data-val="true" data-val-number="欄位 AuthorID 必須是一個數字。"
data-val-required
="AuthorID 欄位是必需的。" id="AuthorID" name="AuthorID" type="number" value="12" /> <span class="field-validation-valid" data-valmsg-for="AuthorID" 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="1000000.00" /> <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span> </div> <div class="editor-label"> <label for="PublishDate">PublishDate</label> </div> <div class="editor-field"> <input class="text-box single-line" data-val="true" data-val-date="欄位 PublishDate 必須是日期。"
data-val-required
="PublishDate 欄位是必需的。" id="PublishDate" name="PublishDate" type="datetime" value="2013/1/1 0:00:00" /> <span class="field-validation-valid" data-valmsg-for="PublishDate" data-valmsg-replace="true"></span> </div> <p> <input type="submit" value="Save" /> </p> </fieldset> </form>

 

      其中最後一個<input>元素設定為Submit,用於提交HTML <form>中的表格資料到/Book/Edit URL

 

處理POST請求 
       下面的程式碼示例,顯示了Edit操作方法的HttpPost版本。

[HttpPost] 

        public ActionResult Edit(Book book)

        {

            if (ModelState.IsValid)

            {

                db.Entry(book).State = EntityState.Modified;

                db.SaveChanges();

                return RedirectToAction("Index");

            }

            return View(book);

        }

        ASP.NET MVC Model Binder簡單的說就是控制器中的Action方法需要引數資料;而這些引數資料包含在HTTP請求中,包括表單上的ValueURL中的引數等。通過Model Binder的功能將表單上的ValueURL中的引數換成Book物件,然後將Book物件繫結到Action操作方法中的引數上面。其中ModelState.IsValid方法驗證使用者提交的表單中的資料是否可以被用於修改(編輯或更新)一個Book物件。如果資料是有效的,Book資料將被儲存到資料庫的Book集合中(BookDBContext例項)。新的Book資料是通過呼叫BookDBContextSaveChanges方法儲存到資料庫中。儲存資料後,程式碼將使用者重定向到BookController類的Index操作,同時在瀏覽器中顯示最新的Book列表。 
        如果提交過來的表單中的值是無效的,這些值將重新顯示在瀏覽器的頁面中。在Edit.cshtml檢視模板的Html.ValidationMessageFor助手方法顯示相應的錯誤訊息。如下圖。

 

          請注意,ASP.NET MVC 4.0 已經支援jQuery的驗證方法,在非英語語言環境中使用逗號(“,”)代替小數點,你必須包括globalize.js和你自己所需要的特定語言的globalize.cultures.js檔案(從https://github.com/ jQuery/ globalize 下載)和JavaScript中使用Globalize.parseFloat。下面的程式碼顯示了修改Views\Book\ Edit.cshtml檔案中顯示法語(“fr-FR”)

 

@section Scripts {

    @Scripts.Render("~/bundles/jqueryval")

    <script src="~/Scripts/globalize.js"></script>

    <script src="~/Scripts/globalize.culture.fr-FR.js"></script>

    <script>

        $.validator.methods.number = function (value, element) {

            return this.optional(element) ||

                !isNaN(Globalize.parseFloat(value));

        }

        $(document).ready(function () {

            Globalize.culture('fr-FR');

        });

    </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>

}

 

         小數字段可能需要使用一個逗號,不是小數點。作為一個臨時的解決辦法,你可以在全球化的元素新增到專案的根目錄下的Web.config檔案中。下面的程式碼顯示了全球化設定為en-US”

  <system.web>

    <globalization culture ="en-US" />

    <!--elements removed for clarity-->

  </system.web>

 

      說明:所有的建立,編輯,刪除或以其他方式修改資料的方法都是通過HttpPost將資料傳給相應控制器的相應方法。

               HTTPGET方法遵循類似的模式。他們獲取一個書籍(Book)物件(或是物件列表,在Index方法情況下) ,同時將物件資料傳遞給檢視,由檢視進行呈現。 Create方法傳遞一個空的書籍物件給Create檢視。通過HTTP GET式修改資料存在一個安全隱患。使用GET方法修改資料也違反了HTTP的最佳實踐和REST的架構模式,它指定了GET請求不應該改變你的應用程式的狀態。換句話說,執行GET操作應該是一個安全的操作,沒有任何副作用,不會修改你的持久化的資料。

相關文章