ASP.NET Core 中文文檔 第二章 指南(4.6)Controller 方法與視圖

来源:http://www.cnblogs.com/dotNETCoreSG/archive/2016/06/18/aspnetcore-2_4_6-controller-methods-views.html
-Advertisement-
Play Games

原文: "Controller methods and views" 作者: "Rick Anderson" 翻譯: "謝煬(Kiler)" 校對: "孟帥洋(書緣)" 、 "張仁建(第二年.夏)" 、 "許登洋(Seay)" 、 "姚阿勇(Dr.Yao)" 、 "婁宇(Lyrics)" 我們已經初 ...


原文:Controller methods and views
作者:Rick Anderson
翻譯:謝煬(Kiler)
校對:孟帥洋(書緣) 、張仁建(第二年.夏) 、許登洋(Seay) 、姚阿勇(Dr.Yao) 、婁宇(Lyrics)

我們已經初步的創建了一個 movie 應用程式,但是展示並不理想。我們不希望看到 release date 欄位顯示時間並且 ReleaseDate 應該是兩個單詞。
movies-Index

打開 Models/Movie.cs 文件並添加下麵高亮的代碼行:

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; }
}
  • 右鍵點擊紅色波浪線代碼行 > Quick Actions
    Quick Actions

  • 點擊 using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations;

Visual studio 會自動添加 using System.ComponentModel.DataAnnotations; 引用代碼。

讓我們移除多餘的 using 引用代碼。它們預設以灰色字體出現。右鍵點擊 Movie.cs 文件 點擊 > Organize Usings > Remove Unnecessary Usings 菜單。
Remove Unnecessary Usings
更新後的代碼:

using System;
using System.ComponentModel.DataAnnotations;

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; }
    }
}

我們會在下一篇文章中繼續發掘 DataAnnotations 的內容。Display 特性用來指定欄位的顯示名 (在本示例中 “Release Date” 會替代 “ReleaseDate”)。DataType 特性指定數據類型,在本示例是日期類型,所以欄位中存儲的時間信息不會被顯示。

瀏覽 Movies 控制器並把滑鼠懸停於 Edit 鏈接上可以看到目標 URL。
Movies-Edit

EditDetails 以及 Delete 鏈接是由 Views/Movies/Index.cshtml 文件中的 MVC Core Anchor Tag Helper 自動生成的。

<td>
    <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |         //手動高亮
    <a asp-action="Details" asp-route-id="@item.ID">Details</a> |   //手動高亮
    <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>       //手動高亮
</td>

Tag Helpers 允許伺服器端代碼在 Razor 文件中創建和生成 HTML 元素。在上面的代碼中,AnchorTagHelper通過 controller 方法以及路由ID 動態生成 HTML href 屬性值。你可以在你熟悉的瀏覽器中使用 View Source 菜單或者使用 F12 工具來檢查你生成的 HTML 標簽。 F12 工具如下圖。
F12工具

在 Startup.cs 文件中設置回調路由格式。

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");  //手動高亮
});

ASP.NET Core 會把 http://localhost:1234/Movies/Edit/4 轉化成發送到 Movies controller 的 Edit 方法的請求並帶上值為 4 的 ID 參數。(Controller 方法其實就是指代 action 方法。)

Tag Helpers 是 ASP.NET Core 中最受歡迎的新功能之一。 參考 附錄資源 獲取更多信息。

打開 Movies controller 並查看兩個 Edit 方法:
兩個 Edit 方法

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}
// POST: Movies/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for 
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Genre,Price,ReleaseDate,Title")] Movie movie)
{
    if (id != movie.ID)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.ID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction("Index");
    }
    return View(movie);
}

[Bind] 特性是防止 over-posting (過度提交,客戶端可能發送比期望還多的數據,比如只需要2個屬性但是發送了3個屬性)的一種方法。你應該只把需要改變的屬性包含到 [Bind] 特性中。請參閱 Protect your controller from over-posting 獲取更多信息,ViewModels 提供了另一種防止 over-posting 的方法。

請註意帶第二個 Edit 方法被 [HttpPost] 特性所修飾。

[HttpPost] //手動高亮
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Genre,Price,ReleaseDate,Title")] Movie movie)
{
    if (id != movie.ID)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.ID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction("Index");
    }
    return View(movie);
}

[HttpPost]特性指定這個 Edit 方法 只能 被 POST 請求調用。你可以把 [HttpGet] 特性應用到第一個 edit 方法,但是,不是必須的,因為 [HttpGet] 是被預設使用的。

[ValidateAntiForgeryToken] 特性是用來防止偽造請求的,會在(Views/Movies/Edit.cshtml)視圖最終呈現文件中加入反偽造標記和伺服器進行配對。edit 視圖生成反偽造標記請參考 Form Tag Helper

<form asp-action="Edit">

Form Tag Helper 生成一個隱藏域的防偽標記必須和 Movies controller 的 Edit 方法的 [ValidateAntiForgeryToken] 產生的防偽標記相匹配。更多信息請參考 Anti-Request Forgery

HttpGet Edit 方法獲取 movie 的 ID 參數,通過使用 Entity Framework 的 SingleOrDefaultAsync 方法查找 movie,並將選中的 movie 填充到 Edit 視圖。如果 movie 沒有找到,返回 NotFound (HTTP 404) 響應。

// GET: Movies/Edit/5
public async Task<IActionResult> Edit(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
    if (movie == null)
    {
        return NotFound();
    }
    return View(movie);
}

在基架系統創建 Edit 視圖的時候,會檢查 Movie 類併為它的每個屬性生成代碼以呈現 <label> 和 <input> 元素。下麵的例子展示了 Visual Studio 基架系統生成的 Edit 視圖:

@model MvcMovie.Models.Movie //手動高亮

@{
    ViewData["Title"] = "Edit";
}

<h2>Edit</h2>

<form asp-action="Edit">
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <input type="hidden" asp-for="ID" />
        <div class="form-group">
            <label asp-for="Genre" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Genre" class="form-control" />
                <span asp-validation-for="Genre" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Price" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Price" class="form-control" />
                <span asp-validation-for="Price" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <label asp-for="ReleaseDate" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="ReleaseDate" class="form-control" />
                <span asp-validation-for="ReleaseDate" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Title" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

你會註意到為什麼視圖模版文件的頂部會有一行 @model MvcMovie.Models.Movie 聲明呢?— 因為這個聲明指定這個視圖模版的模型期待的類型是 Movie

基架生成的代碼使用幾個 Tag Helper 方法來簡化 HTML 標記。 Label Tag Helper 用來顯示欄位名(“Title”、”ReleaseDate”、”Genre” 或者 “Price”)。Input Tag Helper 用來呈現 HTML <input> 元素。Validation Tag Helper 顯示關聯到屬性的錯誤信息。

運行應用程式並導航到 /Movies URL。單擊 編輯 鏈接。在瀏覽器中查看該頁面的源代碼。為 <form> 元素生成的 HTML 如下所示。

<form action="/Movies/Edit/7" method="post"> //手動高亮
    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        <div class="text-danger" />
        <input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />  //手動高亮
        <div class="form-group">
            <label class="control-label col-md-2" for="Genre" />
            <div class="col-md-10">
                <input class="form-control" type="text" id="Genre" name="Genre" value="Western" />  //手動高亮
                <span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true" />
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-md-2" for="Price" />
            <div class="col-md-10">
                <input class="form-control" type="text" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" value="3.99" /> //手動高亮
                <span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true" />
            </div>
        </div>
        <!-- Markup removed for brevity -->
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" /> //手動高亮
            </div>
        </div>
    </div>
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" /> //手動高亮
</form>

HTML <form> 中的 <input> 元素的 action 屬性用於設置請求發送到 /Movies/Edit/id URL。當點擊 Save 按鈕時表單數據會被髮送到伺服器。在 </form> 元素關閉前最後一行 </form> 展示了 XSRF 生成的隱藏域標識。

處理 POST 請求

下麵的列表顯示了 [HttpPost] 不同版本的 Edit 方法。

[HttpPost]  //手動高亮
[ValidateAntiForgeryToken]  //手動高亮
public async Task<IActionResult> Edit(int id, [Bind("ID,Genre,Price,ReleaseDate,Title")] Movie movie)
{
    if (id != movie.ID)
    {
        return NotFound();
    }

    if (ModelState.IsValid)  //手動高亮
    {
        try
        {
            _context.Update(movie);  //手動高亮
            await _context.SaveChangesAsync();  //手動高亮
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.ID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction("Index");  //手動高亮
    }
    return View(movie);
}

[ValidateAntiForgeryToken] 特性驗證 Form Tag Helper 生成的存放在隱藏域中的 XSRF 反偽造標記。

模型綁定機制以發送表單數據創建 Movie 對象並作為 movie 參數。ModelState.IsValid 方法驗證表單提交的數據可以用來修改(編輯或更新)一個 Movie 對象。如果數據有效,就可以保存。更新(編輯) movie 數據會被存到資料庫通過 database context 的 SaveChangesAsync 方法。數據保存完畢以後,這段代碼將用戶重定向到 MoviesController 類的 Index 方法,這個頁面顯示了改動後最新的Movie集合。

表單數據被髮布到伺服器之前,客戶端校驗會檢查所有欄位上的驗證規則。如果有任何驗證錯誤,則顯示錯誤消息,並且表單數據不會被髮送。如果禁用了 JavaScript,將不會有客戶端驗證,但伺服器端將檢測出發送數據是無效的,表單依舊會顯示出錯誤信息。在稍後的教程中,我們會探討 Model Validation 模型驗證 更多關於驗證的細節。Views/Book/Edit.cshtml 視圖模版中的 Validation Tag Helper 負責顯示錯誤信息。
Model Validation 模型驗證

movie controller 的所有 HttpGet 方法都遵循類似的模式。它們獲取一個對象(或者對象列表,比如 Index),把對象(模型)傳遞到視圖。Create 方法創建一個空的對象到 Create 視圖。諸如 Create、Edit、Delete 等之類的會修改數據的方法都會在 [HttpPost] 版本的重載方法中這樣做(譯者註:執行類似於前文所述的這些操作)。在 HTTP GET 方法中修改數據有安全風險,參考 ASP.NET MVC 提示 #46 – 不要使用刪除鏈接,因為他們製造安全漏洞 。在 HTTP GET 方法中修改數據同樣也違反 HTTP 最佳實踐以及 REST 架構模式,其中規定 GET 請求不應該更改應用程式的狀態。換句話說,執行 GET 操作應該是沒有任何副作用,不會修改您的持久化的數據。

附錄資源

返回目錄


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • REMI 倉庫提供了CentOS和RHEL的核心包的更新版本,尤其是最新的PHP/MySQL系列(註:當你需要一個更新包,而 CentOS/RHEL 沒有及時提供更新時, REMI 倉庫可以幫助你)。 安裝REMI倉庫要記住不要在啟用了REMI倉庫時運行yum update。因為REMI倉庫的包名與 ...
  • 最近在學習unix,但在使用ftp鏈接虛擬機時總是總是各種報錯,查了很多資料,試了很多方法,都有一定的問題,最後也算是久病成醫,這裡給其他跟我一樣小白提供一個比較好的解決方案希望能有所幫助。 Fedora vsftp更新了很多版本更新,我本人認為Fedora vsftp 在Fedora系列里很好使的 ...
  • C# 引用類型和值類型 CLR支持兩種類型:引用類型和值類型。 1.引用類型 (1)記憶體必須從托管堆上分配; (2)堆上分配的每個對象都有一些額外成員(包括“類型對象指針”,“同步塊索引”),這些成員必須初始化; (3)對象的其他位元組總是設為零; (4)從托管堆分配對象時,可能強制執行一次垃圾回收。 ...
  • 分類:C#、VS2015 創建日期:2016-06-19 使用教材:(十二五國家級規劃教材)《C#程式設計及應用教程》(第3版) 一、要點概述 別人提供的類都是為了簡化你的工作量用的,可是實際處理的事情千差萬別,要通過寫代碼做實際的事,你還得自己定義類。因此,先把如何自定義類及其涉及的相關概念和要點... ...
  • .Net中提供了許多方便使用的方法,包括在處理文件中查找文件、拷貝文件等,今天實現的是通過簡易的程式實現增量的備份文件。 首先需要的是選擇備份源文件路徑SourcePath和備份目標文件路徑DestinationPath,然後通過StopWatch統計拷貝所耗費的時間。(註意:使用StopWatch ...
  • C# Code 1 2 3 4 5 6 7 8 9 10 ... ...
  • 第一部分 瞭解C# C#是微軟公司在2000年7月發佈的一種全新且簡單、安全、面向對象的程式設計語言,是專門為.NET的應用而開發的。體現了當今最新的程式設計技術的功能和精華。.NET框架為C#提供了一個強大的、易用的、邏輯結構一致的設計環境。其特點: 語言簡潔 保留了C++的強大功能; 快速應用開 ...
  • 普通上傳 view: Controller: Ajax上傳 用普通的ajax提交表單的時候,不能把文件流傳到後端去,所以要用到jquery.form.js jquery.form.js到官網下載或者從這裡下載:http://pan.baidu.com/s/1c2JS60C view: Control ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...