將檢視新增至 ASP.NET Core MVC 應用程式Add a view to an ASP.NET Core MVC app

作者:Rick AndersonBy Rick Anderson

在本節中,您將修改 HelloWorldController 類別來使用 Razor 檢視檔案,完全封裝對用戶端產生 HTML 回應的處理序。In this section you modify the HelloWorldController class to use Razor view files to cleanly encapsulate the process of generating HTML responses to a client.

您可以使用 Razor 建立檢視範本檔案。You create a view template file using Razor. 以 Razor 為基礎的檢視範本具有 .cshtml 副檔名。Razor-based view templates have a .cshtml file extension. 它們提供了一種使用 C# 建立 HTML 輸出的簡潔方式。They provide an elegant way to create HTML output with C#.

Index 方法目前會傳回字串,內含在控制器類別中已直接書寫好的固定訊息。Currently the Index method returns a string with a message that's hard-coded in the controller class. HelloWorldController 類別中,以下列程式碼取代 Index 方法:In the HelloWorldController class, replace the Index method with the following code:

public IActionResult Index()
{
    return View();
}

上述程式碼會呼叫控制器的 View 方法。The preceding code calls the controller's View method. 它使用檢視範本來產生 HTML 回應。It uses a view template to generate an HTML response. 上述 Index 方法等控制器方法 (也稱為「動作方法」 ) 通常會傳回 IActionResult (或衍生自 ActionResult 的類別),而不會傳回像是 string 的類型。Controller methods (also known as action methods), such as the Index method above, generally return an IActionResult (or a class derived from ActionResult), not a type like string.

新增檢視Add a view

  • 依序以滑鼠右鍵按一下 Views 資料夾、[新增] > [新增資料夾] ,然後將資料夾命名為 HelloWorldRight click on the Views folder, and then Add > New Folder and name the folder HelloWorld.

  • 依序以滑鼠右鍵按一下 Views/HelloWorld 資料夾、[新增] > [新增項目] 。Right click on the Views/HelloWorld folder, and then Add > New Item.

  • 在 [新增項目 - MvcMovie] 對話方塊內In the Add New Item - MvcMovie dialog

    • 在右上角的搜尋方塊中,輸入 viewIn the search box in the upper-right, enter view

    • 選取 [Razor 檢視] Select Razor View

    • 保留 [名稱] 方塊值 Index.cshtmlKeep the Name box value, Index.cshtml.

    • 選取 [新增] Select Add

[新增項目] 對話方塊

使用下列內容取代 Views/HelloWorld/Index.cshtml Razor 檢視檔案的內容:Replace the contents of the Views/HelloWorld/Index.cshtml Razor view file with the following:

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

<h2>Index</h2>

<p>Hello from our View Template!</p>

巡覽至 https://localhost:xxxx/HelloWorldNavigate to https://localhost:xxxx/HelloWorld. HelloWorldController 中的 Index 方法不會執行什麼作業;它會執行陳述式 return View();,其指定方法應使用檢視範本檔案來呈現瀏覽器的回應。The Index method in the HelloWorldController didn't do much; it ran the statement return View();, which specified that the method should use a view template file to render a response to the browser. 因為未指定檢視範本檔案名稱,因此 MVC 預設為使用預設檢視檔案。Because a view template file name wasn't specified, MVC defaulted to using the default view file. 預設檢視檔案與方法 (Index) 擁有相同的名稱,因此會在 /Views/HelloWorld/Index.cshtml 中使用。The default view file has the same name as the method (Index), so in the /Views/HelloWorld/Index.cshtml is used. 下列影像顯示檢視中硬式編碼的字串 "Hello from our View Template!"The image below shows the string "Hello from our View Template!" hard-coded in the view.

瀏覽器視窗

變更檢視和版面配置頁Change views and layout pages

選取功能表連結 (MvcMovieHomePrivacy)。Select the menu links (MvcMovie, Home, and Privacy). 每個頁面會顯示相同的功能表配置。Each page shows the same menu layout. 功能表配置是在 Views/Shared/_Layout.cshtml 檔案中實作。The menu layout is implemented in the Views/Shared/_Layout.cshtml file. 開啟 Views/Shared/_Layout.cshtml 檔案。Open the Views/Shared/_Layout.cshtml file.

版面配置範本可讓您在某個位置指定網站的 HTML 容器配置,然後將它套用到網站中的多個頁面。Layout templates allow you to specify the HTML container layout of your site in one place and then apply it across multiple pages in your site. 找到 @RenderBody() 這行。Find the @RenderBody() line. RenderBody 是顯示您建立之所有檢視特定頁面的預留位置,「包裝」 在版面配置頁中。RenderBody is a placeholder where all the view-specific pages you create show up, wrapped in the layout page. 例如,如果您選取 Privacy 連結,Views/Home/Privacy.cshtml 檢視就會呈現在 RenderBody 方法內。For example, if you select the Privacy link, the Views/Home/Privacy.cshtml view is rendered inside the RenderBody method.

  • 在 title 和 footer 元素中,將 MvcMovie 變更為 Movie AppIn the title and footer elements, change MvcMovie to Movie App.
  • 將錨點元素 <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a> 變更為 <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>Change the anchor element <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MvcMovie</a> to <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>.

下列標記顯示醒目提示的變更:The following markup shows the highlighted changes:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
              crossorigin="anonymous"
              integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
    </environment>
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <partial name="_CookieConsentPartial" />
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2019 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>

    <environment include="Development">
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    </environment>
    <environment exclude="Development">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
                asp-fallback-test="window.jQuery"
                crossorigin="anonymous"
                integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
        </script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js"
                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"
                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
                crossorigin="anonymous"
                integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
        </script>
    </environment>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>

在上述標記中,由於此應用程式未使用區域,因此已省略 asp-area 錨點標籤協助程式屬性In the preceding markup, the asp-area anchor Tag Helper attribute was omitted because this app is not using Areas.

注意:尚未實作 Movies 控制器。Note: The Movies controller has not been implemented. 此時,Movie App 連結無法運作。At this point, the Movie App link is not functional.

儲存您的變更並選取 Privacy 連結。Save your changes and select the Privacy link. 請注意,瀏覽器索引標籤上的標題會顯示 Privacy Policy - Movie App,而不是 Privacy Policy - Mvc MovieNotice how the title on the browser tab displays Privacy Policy - Movie App instead of Privacy Policy - Mvc Movie:

Privacy 索引標籤

選取 Home 連結,並注意標題和錨點文字也要顯示 Movie AppSelect the Home link and notice that the title and anchor text also display Movie App. 我們能夠在版面配置範本中一次進行變更,並讓網站上的所有頁面反映新的連結文字和新的標題。We were able to make the change once in the layout template and have all pages on the site reflect the new link text and new title.

檢查 Views/_ViewStart.cshtml 檔案:Examine the Views/_ViewStart.cshtml file:

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml 檔案會將 Views/Shared/_Layout.cshtml 檔案引入每一個檢視。The Views/_ViewStart.cshtml file brings in the Views/Shared/_Layout.cshtml file to each view. Layout 屬性可用來設定不同的版面配置檢視,或將它設定為 null,因此不會使用任何版面配置檔案。The Layout property can be used to set a different layout view, or set it to null so no layout file will be used.

變更 Views/HelloWorld/Index.cshtml 檢視檔案的標題和 <h2> 元素:Change the title and <h2> element of the Views/HelloWorld/Index.cshtml view file:

@{
    ViewData["Title"] = "Movie List";
}

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

標題和 <h2> 元素略有不同,因此可看出哪一段程式碼變更了顯示。The title and <h2> element are slightly different so you can see which bit of code changes the display.

上述程式碼中的 ViewData["Title"] = "Movie List"; 會將 ViewData 字典的 Title 屬性設定為 "Movie List"。ViewData["Title"] = "Movie List"; in the code above sets the Title property of the ViewData dictionary to "Movie List". Title 屬性則用於版面配置頁中的 <title> HTML 元素:The Title property is used in the <title> HTML element in the layout page:

<title>@ViewData["Title"] - Movie App</title>

儲存變更並巡覽至 https://localhost:xxxx/HelloWorldSave the change and navigate to https://localhost:xxxx/HelloWorld. 請注意,瀏覽器標題、主要標題和次要標題已變更Notice that the browser title, the primary heading, and the secondary headings have changed. (如果您在瀏覽器中沒有看到變更,可能檢視的是快取的內容。(If you don't see changes in the browser, you might be viewing cached content. 請在瀏覽器中按 Ctrl + F5 以強制載入來自伺服器的回應)。瀏覽器標題是以我們在 Index.cshtml 檢視範本中設定的 ViewData["Title"] 和版面配置檔案中新增的額外 "- Movie App" 來建立的。Press Ctrl+F5 in your browser to force the response from the server to be loaded.) The browser title is created with ViewData["Title"] we set in the Index.cshtml view template and the additional "- Movie App" added in the layout file.

同時也請注意,Index.cshtml 檢視範本中的內容如何與 Views/Shared/_Layout.cshtml 檢視範本和已傳送至瀏覽器的單一 HTML 回應合併。Also notice how the content in the Index.cshtml view template was merged with the Views/Shared/_Layout.cshtml view template and a single HTML response was sent to the browser. 版面配置範本可讓您輕鬆進行會套用到應用程式之所有頁面的變更。Layout templates make it really easy to make changes that apply across all of the pages in your application. 若要深入了解,請參閱版面配置To learn more see Layout.

電影清單檢視

然而,我們的這一點點「資料」(在此案例中為 "Hello from our View Template!"Our little bit of "data" (in this case the "Hello from our View Template!" 訊息) 是硬式編碼的資料。message) is hard-coded, though. MVC 應用程式具有 "V" (檢視),並已取得 "C" (控制器),但還沒有 "M" (模型)。The MVC application has a "V" (view) and you've got a "C" (controller), but no "M" (model) yet.

將資料從控制器傳遞至檢視Passing Data from the Controller to the View

回應傳入的 URL 要求時會叫用控制器動作。Controller actions are invoked in response to an incoming URL request. 控制器類別是撰寫處理傳入瀏覽器要求之程式碼的位置。A controller class is where the code is written that handles the incoming browser requests. 控制器會從資料來源擷取資料,並決定要將哪一種回應傳回瀏覽器中。The controller retrieves data from a data source and decides what type of response to send back to the browser. 您可以從控制器使用檢視範本來產生並格式化瀏覽器的 HTML 回應。View templates can be used from a controller to generate and format an HTML response to the browser.

控制器負責提供為了讓檢視範本呈現回應所需的資料。Controllers are responsible for providing the data required in order for a view template to render a response. 最佳做法:檢視範本應該執行商務邏輯,或直接與資料庫互動。A best practice: View templates should not perform business logic or interact with a database directly. 相反地,檢視範本應該只使用由控制器提供給它的資料。Rather, a view template should work only with the data that's provided to it by the controller. 維護這項「關注點分離」,有助於保持程式碼整潔、可測試且可維護。Maintaining this "separation of concerns" helps keep the code clean, testable, and maintainable.

目前,HelloWorldController 類別中的 Welcome 方法會採用 nameID 參數,然後將值直接輸出到瀏覽器。Currently, the Welcome method in the HelloWorldController class takes a name and a ID parameter and then outputs the values directly to the browser. 與其讓控制器以字串方式呈現這個回應,不如變更控制器以改為使用檢視範本。Rather than have the controller render this response as a string, change the controller to use a view template instead. 檢視範本會產生動態回應,這表示必須將適當數量的資料從控制器傳遞至檢視,以便產生回應。The view template generates a dynamic response, which means that appropriate bits of data must be passed from the controller to the view in order to generate the response. 透過讓控制器將檢視範本需要的動態資料 (參數) 放置在檢視範本之後可以存取的 ViewData 字典,即可完成這項操作。Do this by having the controller put the dynamic data (parameters) that the view template needs in a ViewData dictionary that the view template can then access.

HelloWorldController.cs 中變更 Welcome 方法,將 MessageNumTimes 值新增至 ViewData 字典。In HelloWorldController.cs, change the Welcome method to add a Message and NumTimes value to the ViewData dictionary. ViewData 字典是動態物件,這表示您可以使用任何類型;ViewData 物件則要在您於其中放入某個項目之後,才會有定義的屬性。The ViewData dictionary is a dynamic object, which means any type can be used; the ViewData object has no defined properties until you put something inside it. MVC 模型繫結系統會自動將網址列上查詢字串中的具名參數 (namenumTimes) 對應至方法中的參數。The MVC model binding system automatically maps the named parameters (name and numTimes) from the query string in the address bar to parameters in your method. 完整的 HelloWorldController.cs 檔案如下所示:The complete HelloWorldController.cs file looks like this:

using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web;

namespace MvcMovie.Controllers
{
    public class HelloWorldController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public IActionResult Welcome(string name, int numTimes = 1)
        {
            ViewData["Message"] = "Hello " + name;
            ViewData["NumTimes"] = numTimes;

            return View();
        }
    }
}

ViewData 字典物件包含將傳遞至檢視的資料。The ViewData dictionary object contains data that will be passed to the view.

建立名為 Views/HelloWorld/Welcome.cshtml 的 Welcome 檢視範本。Create a Welcome view template named Views/HelloWorld/Welcome.cshtml.

您將在 Welcome.cshtml 檢視範本中建立迴圈,以顯示 "Hello" NumTimes 次。You'll create a loop in the Welcome.cshtml view template that displays "Hello" NumTimes. 使用下列內容取代 Views/HelloWorld/Welcome.cshtml 的內容:Replace the contents of Views/HelloWorld/Welcome.cshtml with the following:

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

<h2>Welcome</h2>

<ul>
    @for (int i = 0; i < (int)ViewData["NumTimes"]; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

儲存變更並瀏覽至下列 URL:Save your changes and browse to the following URL:

https://localhost:xxxx/HelloWorld/Welcome?name=Rick&numtimes=4

資料是使用 MVC 模型繫結器從 URL 取得並傳遞至控制站。Data is taken from the URL and passed to the controller using the MVC model binder . 控制器會將資料封裝成 ViewData 字典,並將該物件傳遞至檢視。The controller packages the data into a ViewData dictionary and passes that object to the view. 接著,檢視會以 HTML 將資料呈現到瀏覽器。The view then renders the data as HTML to the browser.

顯示一個 Welcome 標籤和顯示四次的片語 Hello Rick 的 Privacy 檢視

在上述範例中,使用了 ViewData 字典將資料從控制器傳遞至檢視。In the sample above, the ViewData dictionary was used to pass data from the controller to a view. 稍後在教學課程中,會使用檢視模型將控制器中的資料傳遞至檢視。Later in the tutorial, a view model is used to pass data from a controller to a view. 傳遞資料的檢視模型方法通常比 ViewData 字典方法較為慣用。The view model approach to passing data is generally much preferred over the ViewData dictionary approach. 如需詳細資訊,請參閱何時應該使用 ViewBag、ViewData 或 TempData (英文)。See When to use ViewBag, ViewData, or TempData for more information.

在下一個教學課程中,將會建立電影資料庫。In the next tutorial, a database of movies is created.