共用方式為


第 3 部分:將檢視新增至 ASP.NET Core MVC 應用程式

注意

這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本

警告

不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援原則。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前版本,請參閱本文的 .NET 8 版本

作者:Rick Anderson

在本節中,您將修改 HelloWorldController 類別以使用 Razor 檢視檔案。 這會完全封裝對用戶端產生 HTML 回應的程序。

檢視範本是利用 Razor 建立的。 Razor 型檢視範本:

  • 副檔名為 .cshtml
  • 提供了一種使用 C# 建立 HTML 輸出的簡潔方式。

Index 方法目前會傳回字串,以及一則控制器類別的訊息。 在 HelloWorldController 類別中,以下列程式碼取代 Index 方法:

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

上述 程式碼:

  • 呼叫控制器的 View 方法。
  • 使用檢視範本來產生 HTML 回應。

控制器方法:

  • 稱為動作方法。 例如,前述程式碼中的 Index 動作方法。
  • 通常會傳回 IActionResult 或衍生自 ActionResult 的類別,而不是 string 之類的型別。

新增檢視表

用滑鼠右鍵按一下 Views 資料夾,然後選取 [新增]>[新增資料夾],然後將資料夾命名為 HelloWorld

用滑鼠右鍵按一下 Views/HelloWorld 資料夾,然後選取 [新增]>[新增項目]

在 [新增項目] 對話方塊中,選取 [顯示所有範本]

在 [新增項目 - MvcMovie] 對話方塊:

  • 在右上角的搜尋方塊中,輸入 view
  • 選取 [Razor 檢視 - 空白]
  • 保留 [名稱] 方塊的值 Index.cshtml
  • 選擇新增

[新增項目] 對話方塊

Views/HelloWorld/Index.cshtmlRazor 檢視檔案的內容取代為下列:

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

<h2>Index</h2>

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

瀏覽至 https://localhost:{PORT}/HelloWorld

  • HelloWorldController 中的 Index 方法會執行陳述式 return View();,其指定方法應使用檢視範本檔案來呈現瀏覽器的回應。

  • 未指定檢視範本檔案名稱,因此 MVC 預設為使用預設檢視檔案。 未指定檢視檔案名稱時,系統會傳回預設檢視。 預設檢視的名稱與動作方法相同,在本範例中為 Index。 使用檢視範本 /Views/HelloWorld/Index.cshtml

  • 下圖顯示檢視中硬式編碼的字串 "Hello from our View Template!":

    瀏覽器視窗

變更檢視和版面配置頁

選取功能表連結 MvcMovieHomePrivacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Views/Shared/_Layout.cshtml 檔案中實作。

開啟 Views/Shared/_Layout.cshtml 檔案。

版面配置範本允許:

  • 集中指定網站的 HTML 容器版面配置。
  • 將 HTML 容器版面配置套用至網站的多個頁面。

找到 @RenderBody() 這行。 RenderBody 是顯示您建立之所有檢視特定頁面的預留位置,「包裝」在版面配置頁中。 例如,如果您選取 Privacy 連結,則 Views/Home/Privacy.cshtml 檢視就會呈現在 RenderBody 方法內。

Views/Shared/_Layout.cshtml 檔案的內容取代為下列標記。 所做的變更已醒目提示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/MvcMovie.styles.css" asp-append-version="true" />
</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-fluid">
                <a class="navbar-brand" asp-area="" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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 justify-content-between">
                    <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">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2024 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

上述標記進行了下列變更:

  • 出現 MvcMovie 的三處改為 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>

在上述標記中,由於此應用程式未使用區域,因此省略了asp-area="" 錨點標籤協助程式屬性和屬性值。

注意Movies 控制器尚未實作。 此時,Movie App 連結無法運作。

請儲存變更並選取 Privacy 連結。 請注意,瀏覽器索引標籤上的標題會顯示 Privacy Policy - Movie App 而不是 Privacy Policy - MvcMovie

Privacy 索引標籤

選取 Home 連結。

請注意,標題和錨點文字會顯示 Movie App。 在版面配置範本中所做的變更一次,而網站上的所有頁面都會反映新的連結文字和新標題。

檢查 Views/_ViewStart.cshtml 檔案:

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml 檔案會將 Views/Shared/_Layout.cshtml 檔案帶入每個檢視。 Layout 屬性可用來設定不同的版面配置檢視,或將它設定為 null,因此不會使用任何版面配置檔案。

開啟 Views/HelloWorld/Index.cshtml 檢視檔案。

依照下列醒目提示,變更標題和 <h2> 元素:

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

<h2>My Movie List</h2>

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

標題和 <h2> 元素略有不同,因此可以清楚知道是程式碼的哪個部分變更了顯示畫面。

上述程式碼中的 ViewData["Title"] = "Movie List"; 會將 ViewData 字典的 Title 屬性設定為 "Movie List"。 Title 屬性則用於版面配置頁中的 <title> HTML 元素:

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

儲存變更並巡覽至 https://localhost:{PORT}/HelloWorld

請注意,下列項目已變更:

  • 瀏覽器標題。
  • 主要標題。
  • 次要標題。

如果瀏覽器中沒有任何變更,可以快取正在檢視的內容。 請在瀏覽器中按 Ctrl + F5 以強制載入來自伺服器的回應。 瀏覽器標題是以我們在 Index.cshtml 檢視範本中設定的 ViewData["Title"] 和版面配置檔案中新增的額外 "- Movie App" 來建立的。

Index.cshtml 檢視範本中的內容會與 Views/Shared/_Layout.cshtml 檢視範本合併。 單一 HTML 回應會傳送到瀏覽器。 版面配置範本可讓您輕鬆進行變更,然後套用到應用程式中的所有頁面。 若要深入了解,請參閱版面配置

電影清單檢視

不過,有一小部分「資料」:"Hello from our View Template!" 訊息是硬式編碼。 MVC 應用程式有一個 "V" (檢視)、一個 "C" (控制器),但還沒有 "M" (模型)。

將資料從控制器傳遞至檢視

回應傳入的 URL 要求時會叫用控制器動作。 控制器類別是撰寫處理傳入瀏覽器要求之程式碼的位置。 控制器會從資料來源擷取資料,並決定要將哪一種回應傳回瀏覽器中。 您可以從控制器使用檢視範本來產生並格式化瀏覽器的 HTML 回應。

控制器負責提供為了讓檢視範本呈現回應所需的資料。

檢視範本應該:

  • 執行商務邏輯
  • 直接與資料庫互動。

檢視範本應該只使用由控制器提供的資料。 維護此「關注點分離」有助於讓程式碼保持:

  • 乾淨。
  • 可測試。
  • 可維護。

目前,HelloWorldController 類別中的 Welcome 方法會採用 nameID 參數,然後將值直接輸出到瀏覽器。

與其讓控制器以字串方式呈現這個回應,不如變更控制器以改為使用檢視範本。 檢視範本會產生動態回應,這表示必須將適當的資料從控制器傳遞至檢視以產生回應。 若要執行此作業,可讓控制器將檢視範本需要的動態資料 (參數) 放置在 ViewData 字典。 然後,檢視範本就可以存取動態資料。

HelloWorldController.cs 中變更 Welcome 方法,將 MessageNumTimes 值新增至 ViewData 字典。

ViewData 字典是動態物件,這表示可以使用任何型別。 在新增任何項目之前,ViewData 物件沒有已定義的屬性。 MVC 模型繫結系統會自動將查詢字串中的具名參數 namenumTimes 對應至方法中的參數。 完整的 HelloWorldController

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 字典物件包含將傳遞至檢視的資料。

建立名為 Views/HelloWorld/Welcome.cshtml 的 Welcome 檢視範本。

您將在顯示 "Hello" NumTimesWelcome.cshtml 檢視範本中建立迴圈。 將 Views/HelloWorld/Welcome.cshtml 的內容取代成下列:

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

<h2>Welcome</h2>

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

儲存變更並瀏覽至下列 URL:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

資料是使用 MVC 模型繫結器從 URL 取得並傳遞至控制站。 控制器會將資料封裝成 ViewData 字典,並將該物件傳遞至檢視。 接著,檢視會以 HTML 將資料呈現到瀏覽器。

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

在前述範例中,使用了 ViewData 字典將資料從控制器傳遞至檢視。 稍後在教學課程中,會使用檢視模型將控制器中的資料傳遞至檢視。 優先使用檢視模型方法來傳遞資料,然後才是 ViewData 字典方法。

在下一個教學課程中,將會建立電影資料庫。

在本節中,您將修改 HelloWorldController 類別以使用 Razor 檢視檔案。 這會完全封裝對用戶端產生 HTML 回應的程序。

檢視範本是利用 Razor 建立的。 Razor 型檢視範本:

  • 副檔名為 .cshtml
  • 提供了一種使用 C# 建立 HTML 輸出的簡潔方式。

Index 方法目前會傳回字串,以及一則控制器類別的訊息。 在 HelloWorldController 類別中,以下列程式碼取代 Index 方法:

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

上述 程式碼:

  • 呼叫控制器的 View 方法。
  • 使用檢視範本來產生 HTML 回應。

控制器方法:

  • 稱為動作方法。 例如,前述程式碼中的 Index 動作方法。
  • 通常會傳回 IActionResult 或衍生自 ActionResult 的類別,而不是 string 之類的型別。

新增檢視表

用滑鼠右鍵按一下 Views 資料夾,然後選取 [新增]>[新增資料夾],然後將資料夾命名為 HelloWorld

用滑鼠右鍵按一下 Views/HelloWorld 資料夾,然後選取 [新增]>[新增項目]

在 [新增項目] 對話方塊中,選取 [顯示所有範本]

在 [新增項目 - MvcMovie] 對話方塊:

  • 在右上角的搜尋方塊中,輸入 view
  • 選取 [Razor 檢視 - 空白]
  • 保留 [名稱] 方塊的值 Index.cshtml
  • 選擇新增

[新增項目] 對話方塊

Views/HelloWorld/Index.cshtmlRazor 檢視檔案的內容取代為下列:

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

<h2>Index</h2>

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

瀏覽至 https://localhost:{PORT}/HelloWorld

  • HelloWorldController 中的 Index 方法會執行陳述式 return View();,其指定方法應使用檢視範本檔案來呈現瀏覽器的回應。

  • 未指定檢視範本檔案名稱,因此 MVC 預設為使用預設檢視檔案。 未指定檢視檔案名稱時,系統會傳回預設檢視。 預設檢視的名稱與動作方法相同,在本範例中為 Index。 使用檢視範本 /Views/HelloWorld/Index.cshtml

  • 下圖顯示檢視中硬式編碼的字串 "Hello from our View Template!":

    瀏覽器視窗

變更檢視和版面配置頁

選取功能表連結 MvcMovieHomePrivacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Views/Shared/_Layout.cshtml 檔案中實作。

開啟 Views/Shared/_Layout.cshtml 檔案。

版面配置範本允許:

  • 集中指定網站的 HTML 容器版面配置。
  • 將 HTML 容器版面配置套用至網站的多個頁面。

找到 @RenderBody() 這行。 RenderBody 是顯示您建立之所有檢視特定頁面的預留位置,「包裝」在版面配置頁中。 例如,如果您選取 Privacy 連結,則 Views/Home/Privacy.cshtml 檢視就會呈現在 RenderBody 方法內。

Views/Shared/_Layout.cshtml 檔案的內容取代為下列標記。 所做的變更已醒目提示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</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-fluid">
                <a class="navbar-brand" asp-area="" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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 justify-content-between">
                    <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">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2023 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

上述標記進行了下列變更:

  • 出現 MvcMovie 的三處改為 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>

在上述標記中,由於此應用程式未使用區域,因此省略了asp-area="" 錨點標籤協助程式屬性和屬性值。

注意Movies 控制器尚未實作。 此時,Movie App 連結無法運作。

請儲存變更並選取 Privacy 連結。 請注意,瀏覽器索引標籤上的標題會顯示 Privacy Policy - Movie App 而不是 Privacy Policy - MvcMovie

Privacy 索引標籤

選取 Home 連結。

請注意,標題和錨點文字會顯示 Movie App。 在版面配置範本中所做的變更一次,而網站上的所有頁面都會反映新的連結文字和新標題。

檢查 Views/_ViewStart.cshtml 檔案:

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml 檔案會將 Views/Shared/_Layout.cshtml 檔案帶入每個檢視。 Layout 屬性可用來設定不同的版面配置檢視,或將它設定為 null,因此不會使用任何版面配置檔案。

開啟 Views/HelloWorld/Index.cshtml 檢視檔案。

依照下列醒目提示,變更標題和 <h2> 元素:

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

<h2>My Movie List</h2>

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

標題和 <h2> 元素略有不同,因此可以清楚知道是程式碼的哪個部分變更了顯示畫面。

上述程式碼中的 ViewData["Title"] = "Movie List"; 會將 ViewData 字典的 Title 屬性設定為 "Movie List"。 Title 屬性則用於版面配置頁中的 <title> HTML 元素:

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

儲存變更並巡覽至 https://localhost:{PORT}/HelloWorld

請注意,下列項目已變更:

  • 瀏覽器標題。
  • 主要標題。
  • 次要標題。

如果瀏覽器中沒有任何變更,可以快取正在檢視的內容。 請在瀏覽器中按 Ctrl + F5 以強制載入來自伺服器的回應。 瀏覽器標題是以我們在 Index.cshtml 檢視範本中設定的 ViewData["Title"] 和版面配置檔案中新增的額外 "- Movie App" 來建立的。

Index.cshtml 檢視範本中的內容會與 Views/Shared/_Layout.cshtml 檢視範本合併。 單一 HTML 回應會傳送到瀏覽器。 版面配置範本可讓您輕鬆進行變更,然後套用到應用程式中的所有頁面。 若要深入了解,請參閱版面配置

電影清單檢視

不過,有一小部分「資料」:"Hello from our View Template!" 訊息是硬式編碼。 MVC 應用程式有一個 "V" (檢視)、一個 "C" (控制器),但還沒有 "M" (模型)。

將資料從控制器傳遞至檢視

回應傳入的 URL 要求時會叫用控制器動作。 控制器類別是撰寫處理傳入瀏覽器要求之程式碼的位置。 控制器會從資料來源擷取資料,並決定要將哪一種回應傳回瀏覽器中。 您可以從控制器使用檢視範本來產生並格式化瀏覽器的 HTML 回應。

控制器負責提供為了讓檢視範本呈現回應所需的資料。

檢視範本應該:

  • 執行商務邏輯
  • 直接與資料庫互動。

檢視範本應該只使用由控制器提供的資料。 維護此「關注點分離」有助於讓程式碼保持:

  • 乾淨。
  • 可測試。
  • 可維護。

目前,HelloWorldController 類別中的 Welcome 方法會採用 nameID 參數,然後將值直接輸出到瀏覽器。

與其讓控制器以字串方式呈現這個回應,不如變更控制器以改為使用檢視範本。 檢視範本會產生動態回應,這表示必須將適當的資料從控制器傳遞至檢視以產生回應。 若要執行此作業,可讓控制器將檢視範本需要的動態資料 (參數) 放置在 ViewData 字典。 然後,檢視範本就可以存取動態資料。

HelloWorldController.cs 中變更 Welcome 方法,將 MessageNumTimes 值新增至 ViewData 字典。

ViewData 字典是動態物件,這表示可以使用任何型別。 在新增任何項目之前,ViewData 物件沒有已定義的屬性。 MVC 模型繫結系統會自動將查詢字串中的具名參數 namenumTimes 對應至方法中的參數。 完整的 HelloWorldController

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 字典物件包含將傳遞至檢視的資料。

建立名為 Views/HelloWorld/Welcome.cshtml 的 Welcome 檢視範本。

您將在顯示 "Hello" NumTimesWelcome.cshtml 檢視範本中建立迴圈。 將 Views/HelloWorld/Welcome.cshtml 的內容取代成下列:

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

<h2>Welcome</h2>

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

儲存變更並瀏覽至下列 URL:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

資料是使用 MVC 模型繫結器從 URL 取得並傳遞至控制站。 控制器會將資料封裝成 ViewData 字典,並將該物件傳遞至檢視。 接著,檢視會以 HTML 將資料呈現到瀏覽器。

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

在前述範例中,使用了 ViewData 字典將資料從控制器傳遞至檢視。 稍後在教學課程中,會使用檢視模型將控制器中的資料傳遞至檢視。 優先使用檢視模型方法來傳遞資料,然後才是 ViewData 字典方法。

在下一個教學課程中,將會建立電影資料庫。

在本節中,您將修改 HelloWorldController 類別以使用 Razor 檢視檔案。 這會完全封裝對用戶端產生 HTML 回應的程序。

檢視範本是利用 Razor 建立的。 Razor 型檢視範本:

  • 副檔名為 .cshtml
  • 提供了一種使用 C# 建立 HTML 輸出的簡潔方式。

Index 方法目前會傳回字串,以及一則控制器類別的訊息。 在 HelloWorldController 類別中,以下列程式碼取代 Index 方法:

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

上述 程式碼:

  • 呼叫控制器的 View 方法。
  • 使用檢視範本來產生 HTML 回應。

控制器方法:

  • 稱為動作方法。 例如,前述程式碼中的 Index 動作方法。
  • 通常會傳回 IActionResult 或衍生自 ActionResult 的類別,而不是 string 之類的型別。

新增檢視表

用滑鼠右鍵按一下 Views 資料夾,然後選取 [新增]>[新增資料夾],然後將資料夾命名為 HelloWorld

用滑鼠右鍵按一下 Views/HelloWorld 資料夾,然後選取 [新增]>[新增項目]

在 [新增項目 - MvcMovie] 對話方塊:

  • 在右上角的搜尋方塊中,輸入 view
  • 選取 [Razor 檢視 - 空白]
  • 保留 [名稱] 方塊的值 Index.cshtml
  • 選擇新增

[新增項目] 對話方塊

Views/HelloWorld/Index.cshtmlRazor 檢視檔案的內容取代為下列:

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

<h2>Index</h2>

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

瀏覽至 https://localhost:{PORT}/HelloWorld

  • HelloWorldController 中的 Index 方法會執行陳述式 return View();,其指定方法應使用檢視範本檔案來呈現瀏覽器的回應。

  • 未指定檢視範本檔案名稱,因此 MVC 預設為使用預設檢視檔案。 未指定檢視檔案名稱時,系統會傳回預設檢視。 預設檢視的名稱與動作方法相同,在本範例中為 Index。 使用檢視範本 /Views/HelloWorld/Index.cshtml

  • 下圖顯示檢視中硬式編碼的字串 "Hello from our View Template!":

    瀏覽器視窗

變更檢視和版面配置頁

選取功能表連結 MvcMovieHomePrivacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Views/Shared/_Layout.cshtml 檔案中實作。

開啟 Views/Shared/_Layout.cshtml 檔案。

版面配置範本允許:

  • 集中指定網站的 HTML 容器版面配置。
  • 將 HTML 容器版面配置套用至網站的多個頁面。

找到 @RenderBody() 這行。 RenderBody 是顯示您建立之所有檢視特定頁面的預留位置,「包裝」在版面配置頁中。 例如,如果您選取 Privacy 連結,則 Views/Home/Privacy.cshtml 檢視就會呈現在 RenderBody 方法內。

Views/Shared/_Layout.cshtml 檔案的內容取代為下列標記。 所做的變更已醒目提示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</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-fluid">
                <a class="navbar-brand" asp-area="" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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 justify-content-between">
                    <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">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2022 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

上述標記進行了下列變更:

  • 出現 MvcMovie 的三處改為 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>

在上述標記中,由於此應用程式未使用區域,因此省略了asp-area="" 錨點標籤協助程式屬性和屬性值。

注意Movies 控制器尚未實作。 此時,Movie App 連結無法運作。

請儲存變更並選取 Privacy 連結。 請注意,瀏覽器索引標籤上的標題會顯示 Privacy Policy - Movie App 而不是 Privacy Policy - MvcMovie

Privacy 索引標籤

選取 Home 連結。

請注意,標題和錨點文字會顯示 Movie App。 在版面配置範本中所做的變更一次,而網站上的所有頁面都會反映新的連結文字和新標題。

檢查 Views/_ViewStart.cshtml 檔案:

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml 檔案會將 Views/Shared/_Layout.cshtml 檔案帶入每個檢視。 Layout 屬性可用來設定不同的版面配置檢視,或將它設定為 null,因此不會使用任何版面配置檔案。

開啟 Views/HelloWorld/Index.cshtml 檢視檔案。

依照下列醒目提示,變更標題和 <h2> 元素:

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

<h2>My Movie List</h2>

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

標題和 <h2> 元素略有不同,因此可以清楚知道是程式碼的哪個部分變更了顯示畫面。

上述程式碼中的 ViewData["Title"] = "Movie List"; 會將 ViewData 字典的 Title 屬性設定為 "Movie List"。 Title 屬性則用於版面配置頁中的 <title> HTML 元素:

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

儲存變更並巡覽至 https://localhost:{PORT}/HelloWorld

請注意,下列項目已變更:

  • 瀏覽器標題。
  • 主要標題。
  • 次要標題。

如果瀏覽器中沒有任何變更,可以快取正在檢視的內容。 請在瀏覽器中按 Ctrl + F5 以強制載入來自伺服器的回應。 瀏覽器標題是以我們在 Index.cshtml 檢視範本中設定的 ViewData["Title"] 和版面配置檔案中新增的額外 "- Movie App" 來建立的。

Index.cshtml 檢視範本中的內容會與 Views/Shared/_Layout.cshtml 檢視範本合併。 單一 HTML 回應會傳送到瀏覽器。 版面配置範本可讓您輕鬆進行變更,然後套用到應用程式中的所有頁面。 若要深入了解,請參閱版面配置

電影清單檢視

不過,有一小部分「資料」:"Hello from our View Template!" 訊息是硬式編碼。 MVC 應用程式有一個 "V" (檢視)、一個 "C" (控制器),但還沒有 "M" (模型)。

將資料從控制器傳遞至檢視

回應傳入的 URL 要求時會叫用控制器動作。 控制器類別是撰寫處理傳入瀏覽器要求之程式碼的位置。 控制器會從資料來源擷取資料,並決定要將哪一種回應傳回瀏覽器中。 您可以從控制器使用檢視範本來產生並格式化瀏覽器的 HTML 回應。

控制器負責提供為了讓檢視範本呈現回應所需的資料。

檢視範本應該:

  • 執行商務邏輯
  • 直接與資料庫互動。

檢視範本應該只使用由控制器提供的資料。 維護此「關注點分離」有助於讓程式碼保持:

  • 乾淨。
  • 可測試。
  • 可維護。

目前,HelloWorldController 類別中的 Welcome 方法會採用 nameID 參數,然後將值直接輸出到瀏覽器。

與其讓控制器以字串方式呈現這個回應,不如變更控制器以改為使用檢視範本。 檢視範本會產生動態回應,這表示必須將適當的資料從控制器傳遞至檢視以產生回應。 若要執行此作業,可讓控制器將檢視範本需要的動態資料 (參數) 放置在 ViewData 字典。 然後,檢視範本就可以存取動態資料。

HelloWorldController.cs 中變更 Welcome 方法,將 MessageNumTimes 值新增至 ViewData 字典。

ViewData 字典是動態物件,這表示可以使用任何型別。 在新增任何項目之前,ViewData 物件沒有已定義的屬性。 MVC 模型繫結系統會自動將查詢字串中的具名參數 namenumTimes 對應至方法中的參數。 完整的 HelloWorldController

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 字典物件包含將傳遞至檢視的資料。

建立名為 Views/HelloWorld/Welcome.cshtml 的 Welcome 檢視範本。

您將在顯示 "Hello" NumTimesWelcome.cshtml 檢視範本中建立迴圈。 將 Views/HelloWorld/Welcome.cshtml 的內容取代成下列:

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

<h2>Welcome</h2>

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

儲存變更並瀏覽至下列 URL:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

資料是使用 MVC 模型繫結器從 URL 取得並傳遞至控制站。 控制器會將資料封裝成 ViewData 字典,並將該物件傳遞至檢視。 接著,檢視會以 HTML 將資料呈現到瀏覽器。

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

在前述範例中,使用了 ViewData 字典將資料從控制器傳遞至檢視。 稍後在教學課程中,會使用檢視模型將控制器中的資料傳遞至檢視。 優先使用檢視模型方法來傳遞資料,然後才是 ViewData 字典方法。

在下一個教學課程中,將會建立電影資料庫。

在本節中,您將修改 HelloWorldController 類別以使用 Razor 檢視檔案。 這會完全封裝對用戶端產生 HTML 回應的程序。

檢視範本是利用 Razor 建立的。 Razor 型檢視範本:

  • 副檔名為 .cshtml
  • 提供了一種使用 C# 建立 HTML 輸出的簡潔方式。

Index 方法目前會傳回字串,以及一則控制器類別的訊息。 在 HelloWorldController 類別中,以下列程式碼取代 Index 方法:

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

上述 程式碼:

  • 呼叫控制器的 View 方法。
  • 使用檢視範本來產生 HTML 回應。

控制器方法:

  • 稱為動作方法。 例如,前述程式碼中的 Index 動作方法。
  • 通常會傳回 IActionResult 或衍生自 ActionResult 的類別,而不是 string 之類的型別。

新增檢視表

用滑鼠右鍵按一下 Views 資料夾,然後選取 [新增]>[新增資料夾],然後將資料夾命名為 HelloWorld

用滑鼠右鍵按一下 Views/HelloWorld 資料夾,然後選取 [新增]>[新增項目]

在 [新增項目 - MvcMovie] 對話方塊:

  • 在右上角的搜尋方塊中,輸入 view
  • 選取 [Razor 檢視 - 空白]
  • 保留 [名稱] 方塊的值 Index.cshtml
  • 選擇新增

[新增項目] 對話方塊

Views/HelloWorld/Index.cshtmlRazor 檢視檔案的內容取代為下列:

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

<h2>Index</h2>

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

瀏覽至 https://localhost:{PORT}/HelloWorld

  • HelloWorldController 中的 Index 方法會執行陳述式 return View();,其指定方法應使用檢視範本檔案來呈現瀏覽器的回應。

  • 未指定檢視範本檔案名稱,因此 MVC 預設為使用預設檢視檔案。 未指定檢視檔案名稱時,系統會傳回預設檢視。 預設檢視的名稱與動作方法相同,在本範例中為 Index。 使用檢視範本 /Views/HelloWorld/Index.cshtml

  • 下圖顯示檢視中硬式編碼的字串 "Hello from our View Template!":

    瀏覽器視窗

變更檢視和版面配置頁

選取功能表連結 MvcMovieHomePrivacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Views/Shared/_Layout.cshtml 檔案中實作。

開啟 Views/Shared/_Layout.cshtml 檔案。

版面配置範本允許:

  • 集中指定網站的 HTML 容器版面配置。
  • 將 HTML 容器版面配置套用至網站的多個頁面。

找到 @RenderBody() 這行。 RenderBody 是顯示您建立之所有檢視特定頁面的預留位置,「包裝」在版面配置頁中。 例如,如果您選取 Privacy 連結,則 Views/Home/Privacy.cshtml 檢視就會呈現在 RenderBody 方法內。

Views/Shared/_Layout.cshtml 檔案的內容取代為下列標記。 所做的變更已醒目提示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</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-fluid">
                <a class="navbar-brand" asp-area="" asp-controller="Movies" asp-action="Index">Movie App</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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 justify-content-between">
                    <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">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2021 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

上述標記進行了下列變更:

  • 出現 MvcMovie 的三處改為 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>

在上述標記中,由於此應用程式未使用區域,因此省略了asp-area="" 錨點標籤協助程式屬性和屬性值。

注意Movies 控制器尚未實作。 此時,Movie App 連結無法運作。

請儲存變更並選取 Privacy 連結。 請注意,瀏覽器索引標籤上的標題會顯示 Privacy Policy - Movie App 而不是 Privacy Policy - MvcMovie

Privacy 索引標籤

選取 Home 連結。

請注意,標題和錨點文字會顯示 Movie App。 在版面配置範本中所做的變更一次,而網站上的所有頁面都會反映新的連結文字和新標題。

檢查 Views/_ViewStart.cshtml 檔案:

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml 檔案會將 Views/Shared/_Layout.cshtml 檔案帶入每個檢視。 Layout 屬性可用來設定不同的版面配置檢視,或將它設定為 null,因此不會使用任何版面配置檔案。

開啟 Views/HelloWorld/Index.cshtml 檢視檔案。

依照下列醒目提示,變更標題和 <h2> 元素:

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

<h2>My Movie List</h2>

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

標題和 <h2> 元素略有不同,因此可以清楚知道是程式碼的哪個部分變更了顯示畫面。

上述程式碼中的 ViewData["Title"] = "Movie List"; 會將 ViewData 字典的 Title 屬性設定為 "Movie List"。 Title 屬性則用於版面配置頁中的 <title> HTML 元素:

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

儲存變更並巡覽至 https://localhost:{PORT}/HelloWorld

請注意,下列項目已變更:

  • 瀏覽器標題。
  • 主要標題。
  • 次要標題。

如果瀏覽器中沒有任何變更,可以快取正在檢視的內容。 請在瀏覽器中按 Ctrl + F5 以強制載入來自伺服器的回應。 瀏覽器標題是以我們在 Index.cshtml 檢視範本中設定的 ViewData["Title"] 和版面配置檔案中新增的額外 "- Movie App" 來建立的。

Index.cshtml 檢視範本中的內容會與 Views/Shared/_Layout.cshtml 檢視範本合併。 單一 HTML 回應會傳送到瀏覽器。 版面配置範本可讓您輕鬆進行變更,然後套用到應用程式中的所有頁面。 若要深入了解,請參閱版面配置

電影清單檢視

不過,有一小部分「資料」:"Hello from our View Template!" 訊息是硬式編碼。 MVC 應用程式有一個 "V" (檢視)、一個 "C" (控制器),但還沒有 "M" (模型)。

將資料從控制器傳遞至檢視

回應傳入的 URL 要求時會叫用控制器動作。 控制器類別是撰寫處理傳入瀏覽器要求之程式碼的位置。 控制器會從資料來源擷取資料,並決定要將哪一種回應傳回瀏覽器中。 您可以從控制器使用檢視範本來產生並格式化瀏覽器的 HTML 回應。

控制器負責提供為了讓檢視範本呈現回應所需的資料。

檢視範本應該:

  • 執行商務邏輯
  • 直接與資料庫互動。

檢視範本應該只使用由控制器提供的資料。 維護此「關注點分離」有助於讓程式碼保持:

  • 乾淨。
  • 可測試。
  • 可維護。

目前,HelloWorldController 類別中的 Welcome 方法會採用 nameID 參數,然後將值直接輸出到瀏覽器。

與其讓控制器以字串方式呈現這個回應,不如變更控制器以改為使用檢視範本。 檢視範本會產生動態回應,這表示必須將適當的資料從控制器傳遞至檢視以產生回應。 若要執行此作業,可讓控制器將檢視範本需要的動態資料 (參數) 放置在 ViewData 字典。 然後,檢視範本就可以存取動態資料。

HelloWorldController.cs 中變更 Welcome 方法,將 MessageNumTimes 值新增至 ViewData 字典。

ViewData 字典是動態物件,這表示可以使用任何型別。 在新增任何項目之前,ViewData 物件沒有已定義的屬性。 MVC 模型繫結系統會自動將查詢字串中的具名參數 namenumTimes 對應至方法中的參數。 完整的 HelloWorldController

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 字典物件包含將傳遞至檢視的資料。

建立名為 Views/HelloWorld/Welcome.cshtml 的 Welcome 檢視範本。

您將在顯示 "Hello" NumTimesWelcome.cshtml 檢視範本中建立迴圈。 將 Views/HelloWorld/Welcome.cshtml 的內容取代成下列:

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

<h2>Welcome</h2>

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

儲存變更並瀏覽至下列 URL:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

資料是使用 MVC 模型繫結器從 URL 取得並傳遞至控制站。 控制器會將資料封裝成 ViewData 字典,並將該物件傳遞至檢視。 接著,檢視會以 HTML 將資料呈現到瀏覽器。

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

在前述範例中,使用了 ViewData 字典將資料從控制器傳遞至檢視。 稍後在教學課程中,會使用檢視模型將控制器中的資料傳遞至檢視。 優先使用檢視模型方法來傳遞資料,然後才是 ViewData 字典方法。

在下一個教學課程中,將會建立電影資料庫。

在本節中,您將修改 HelloWorldController 類別以使用 Razor 檢視檔案。 這會完全封裝對用戶端產生 HTML 回應的程序。

檢視範本是利用 Razor 建立的。 Razor 型檢視範本:

  • 副檔名為 .cshtml
  • 提供了一種使用 C# 建立 HTML 輸出的簡潔方式。

Index 方法目前會傳回字串,以及一則控制器類別的訊息。 在 HelloWorldController 類別中,以下列程式碼取代 Index 方法:

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

上述 程式碼:

  • 呼叫控制器的 View 方法。
  • 使用檢視範本來產生 HTML 回應。

控制器方法:

  • 稱為動作方法。 例如,前述程式碼中的 Index 動作方法。
  • 通常會傳回 IActionResult 或衍生自 ActionResult 的類別,而不是 string 之類的型別。

新增檢視表

用滑鼠右鍵按一下 Views 資料夾,然後選取 [新增]>[新增資料夾],然後將資料夾命名為 HelloWorld

用滑鼠右鍵按一下 Views/HelloWorld 資料夾,然後選取 [新增]>[新增項目]

在 [新增項目 - MvcMovie] 對話方塊:

  • 在右上角的搜尋方塊中,輸入 view
  • 選取 [Razor 檢視 - 空白]
  • 保留 [名稱] 方塊的值 Index.cshtml
  • 選擇新增

[新增項目] 對話方塊

Views/HelloWorld/Index.cshtmlRazor 檢視檔案的內容取代為下列:

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

<h2>Index</h2>

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

瀏覽至 https://localhost:{PORT}/HelloWorld

  • HelloWorldController 中的 Index 方法會執行陳述式 return View();,其指定方法應使用檢視範本檔案來呈現瀏覽器的回應。

  • 未指定檢視範本檔案名稱,因此 MVC 預設為使用預設檢視檔案。 未指定檢視檔案名稱時,系統會傳回預設檢視。 預設檢視的名稱與動作方法相同,在本範例中為 Index。 使用檢視範本 /Views/HelloWorld/Index.cshtml

  • 下圖顯示檢視中硬式編碼的字串 "Hello from our View Template!":

    瀏覽器視窗

變更檢視和版面配置頁

選取功能表連結 MvcMovieHomePrivacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Views/Shared/_Layout.cshtml 檔案中實作。

開啟 Views/Shared/_Layout.cshtml 檔案。

版面配置範本允許:

  • 集中指定網站的 HTML 容器版面配置。
  • 將 HTML 容器版面配置套用至網站的多個頁面。

找到 @RenderBody() 這行。 RenderBody 是顯示您建立之所有檢視特定頁面的預留位置,「包裝」在版面配置頁中。 例如,如果您選取 Privacy 連結,則 Views/Home/Privacy.cshtml 檢視就會呈現在 RenderBody 方法內。

Views/Shared/_Layout.cshtml 檔案的內容取代為下列標記。 所做的變更已醒目提示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <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 justify-content-between">
                    <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">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

上述標記進行了下列變更:

  • 出現 MvcMovie 的三處改為 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>

在上述標記中,由於此應用程式未使用區域,因此省略了asp-area="" 錨點標籤協助程式屬性和屬性值。

注意Movies 控制器尚未實作。 此時,Movie App 連結無法運作。

請儲存變更並選取 Privacy 連結。 請注意,瀏覽器索引標籤上的標題會顯示 Privacy Policy - Movie App 而不是 Privacy Policy - MvcMovie

Privacy 索引標籤

選取 Home 連結。

請注意,標題和錨點文字會顯示 Movie App。 在版面配置範本中所做的變更一次,而網站上的所有頁面都會反映新的連結文字和新標題。

檢查 Views/_ViewStart.cshtml 檔案:

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml 檔案會將 Views/Shared/_Layout.cshtml 檔案帶入每個檢視。 Layout 屬性可用來設定不同的版面配置檢視,或將它設定為 null,因此不會使用任何版面配置檔案。

開啟 Views/HelloWorld/Index.cshtml 檢視檔案。

依照下列醒目提示,變更標題和 <h2> 元素:

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

<h2>My Movie List</h2>

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

標題和 <h2> 元素略有不同,因此可以清楚知道是程式碼的哪個部分變更了顯示畫面。

上述程式碼中的 ViewData["Title"] = "Movie List"; 會將 ViewData 字典的 Title 屬性設定為 "Movie List"。 Title 屬性則用於版面配置頁中的 <title> HTML 元素:

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

儲存變更並巡覽至 https://localhost:{PORT}/HelloWorld

請注意,下列項目已變更:

  • 瀏覽器標題。
  • 主要標題。
  • 次要標題。

如果瀏覽器中沒有任何變更,可以快取正在檢視的內容。 請在瀏覽器中按 Ctrl + F5 以強制載入來自伺服器的回應。 瀏覽器標題是以我們在 Index.cshtml 檢視範本中設定的 ViewData["Title"] 和版面配置檔案中新增的額外 "- Movie App" 來建立的。

Index.cshtml 檢視範本中的內容會與 Views/Shared/_Layout.cshtml 檢視範本合併。 單一 HTML 回應會傳送到瀏覽器。 版面配置範本可讓您輕鬆進行變更,然後套用到應用程式中的所有頁面。 若要深入了解,請參閱版面配置

電影清單檢視

不過,有一小部分「資料」:"Hello from our View Template!" 訊息是硬式編碼。 MVC 應用程式有一個 "V" (檢視)、一個 "C" (控制器),但還沒有 "M" (模型)。

將資料從控制器傳遞至檢視

回應傳入的 URL 要求時會叫用控制器動作。 控制器類別是撰寫處理傳入瀏覽器要求之程式碼的位置。 控制器會從資料來源擷取資料,並決定要將哪一種回應傳回瀏覽器中。 您可以從控制器使用檢視範本來產生並格式化瀏覽器的 HTML 回應。

控制器負責提供為了讓檢視範本呈現回應所需的資料。

檢視範本應該:

  • 執行商務邏輯
  • 直接與資料庫互動。

檢視範本應該只使用由控制器提供的資料。 維護此「關注點分離」有助於讓程式碼保持:

  • 乾淨。
  • 可測試。
  • 可維護。

目前,HelloWorldController 類別中的 Welcome 方法會採用 nameID 參數,然後將值直接輸出到瀏覽器。

與其讓控制器以字串方式呈現這個回應,不如變更控制器以改為使用檢視範本。 檢視範本會產生動態回應,這表示必須將適當的資料從控制器傳遞至檢視以產生回應。 若要執行此作業,可讓控制器將檢視範本需要的動態資料 (參數) 放置在 ViewData 字典。 然後,檢視範本就可以存取動態資料。

HelloWorldController.cs 中變更 Welcome 方法,將 MessageNumTimes 值新增至 ViewData 字典。

ViewData 字典是動態物件,這表示可以使用任何型別。 在新增任何項目之前,ViewData 物件沒有已定義的屬性。 MVC 模型繫結系統會自動將查詢字串中的具名參數 namenumTimes 對應至方法中的參數。 完整的 HelloWorldController

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 字典物件包含將傳遞至檢視的資料。

建立名為 Views/HelloWorld/Welcome.cshtml 的 Welcome 檢視範本。

您將在顯示 "Hello" NumTimesWelcome.cshtml 檢視範本中建立迴圈。 將 Views/HelloWorld/Welcome.cshtml 的內容取代成下列:

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

<h2>Welcome</h2>

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

儲存變更並瀏覽至下列 URL:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

資料是使用 MVC 模型繫結器從 URL 取得並傳遞至控制站。 控制器會將資料封裝成 ViewData 字典,並將該物件傳遞至檢視。 接著,檢視會以 HTML 將資料呈現到瀏覽器。

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

在前述範例中,使用了 ViewData 字典將資料從控制器傳遞至檢視。 稍後在教學課程中,會使用檢視模型將控制器中的資料傳遞至檢視。 優先使用檢視模型方法來傳遞資料,然後才是 ViewData 字典方法。

在下一個教學課程中,將會建立電影資料庫。

在本節中,您將修改 HelloWorldController 類別以使用 Razor 檢視檔案。 這會完全封裝對用戶端產生 HTML 回應的程序。

檢視範本是利用 Razor 建立的。 Razor 型檢視範本:

  • 副檔名為 .cshtml
  • 提供了一種使用 C# 建立 HTML 輸出的簡潔方式。

Index 方法目前會傳回字串,以及一則控制器類別的訊息。 在 HelloWorldController 類別中,以下列程式碼取代 Index 方法:

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

上述 程式碼:

  • 呼叫控制器的 View 方法。
  • 使用檢視範本來產生 HTML 回應。

控制器方法:

  • 稱為動作方法。 例如,前述程式碼中的 Index 動作方法。
  • 通常會傳回 IActionResult 或衍生自 ActionResult 的類別,而不是 string 之類的型別。

新增檢視表

用滑鼠右鍵按一下 Views 資料夾,然後選取 [新增]>[新增資料夾],然後將資料夾命名為 HelloWorld

用滑鼠右鍵按一下 Views/HelloWorld 資料夾,然後選取 [新增]>[新增項目]

在 [新增項目 - MvcMovie] 對話方塊:

  • 在右上角的搜尋方塊中,輸入 view
  • 選取 [Razor 檢視 - 空白]
  • 保留 [名稱] 方塊的值 Index.cshtml
  • 選擇新增

[新增項目] 對話方塊

Views/HelloWorld/Index.cshtmlRazor 檢視檔案的內容取代為下列:

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

<h2>Index</h2>

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

瀏覽至 https://localhost:{PORT}/HelloWorld

  • HelloWorldController 中的 Index 方法會執行陳述式 return View();,其指定方法應使用檢視範本檔案來呈現瀏覽器的回應。

  • 未指定檢視範本檔案名稱,因此 MVC 預設為使用預設檢視檔案。 未指定檢視檔案名稱時,系統會傳回預設檢視。 預設檢視的名稱與動作方法相同,在本範例中為 Index。 使用檢視範本 /Views/HelloWorld/Index.cshtml

  • 下圖顯示檢視中硬式編碼的字串 "Hello from our View Template!":

    瀏覽器視窗

變更檢視和版面配置頁

選取功能表連結 MvcMovieHomePrivacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Views/Shared/_Layout.cshtml 檔案中實作。

開啟 Views/Shared/_Layout.cshtml 檔案。

版面配置範本允許:

  • 集中指定網站的 HTML 容器版面配置。
  • 將 HTML 容器版面配置套用至網站的多個頁面。

找到 @RenderBody() 這行。 RenderBody 是顯示您建立之所有檢視特定頁面的預留位置,「包裝」在版面配置頁中。 例如,如果您選取 Privacy 連結,則 Views/Home/Privacy.cshtml 檢視就會呈現在 RenderBody 方法內。

Views/Shared/_Layout.cshtml 檔案的內容取代為下列標記。 所做的變更已醒目提示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Movie App</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <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">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2020 - Movie App - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @RenderSection("Scripts", required: false)
</body>
</html>

上述標記進行了下列變更:

  • 出現 MvcMovie 的三處改為 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>

在上述標記中,由於此應用程式未使用區域,因此省略了asp-area="" 錨點標籤協助程式屬性和屬性值。

注意Movies 控制器尚未實作。 此時,Movie App 連結無法運作。

請儲存變更並選取 Privacy 連結。 請注意,瀏覽器索引標籤上的標題會顯示 Privacy Policy - Movie App 而不是 Privacy Policy - MvcMovie

Privacy 索引標籤

選取 Home 連結。

請注意,標題和錨點文字會顯示 Movie App。 在版面配置範本中所做的變更一次,而網站上的所有頁面都會反映新的連結文字和新標題。

檢查 Views/_ViewStart.cshtml 檔案:

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml 檔案會將 Views/Shared/_Layout.cshtml 檔案帶入每個檢視。 Layout 屬性可用來設定不同的版面配置檢視,或將它設定為 null,因此不會使用任何版面配置檔案。

開啟 Views/HelloWorld/Index.cshtml 檢視檔案。

依照下列醒目提示,變更標題和 <h2> 元素:

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

<h2>My Movie List</h2>

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

標題和 <h2> 元素略有不同,因此可以清楚知道是程式碼的哪個部分變更了顯示畫面。

上述程式碼中的 ViewData["Title"] = "Movie List"; 會將 ViewData 字典的 Title 屬性設定為 "Movie List"。 Title 屬性則用於版面配置頁中的 <title> HTML 元素:

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

儲存變更並巡覽至 https://localhost:{PORT}/HelloWorld

請注意,下列項目已變更:

  • 瀏覽器標題。
  • 主要標題。
  • 次要標題。

如果瀏覽器中沒有任何變更,可以快取正在檢視的內容。 請在瀏覽器中按 Ctrl + F5 以強制載入來自伺服器的回應。 瀏覽器標題是以我們在 Index.cshtml 檢視範本中設定的 ViewData["Title"] 和版面配置檔案中新增的額外 "- Movie App" 來建立的。

Index.cshtml 檢視範本中的內容會與 Views/Shared/_Layout.cshtml 檢視範本合併。 單一 HTML 回應會傳送到瀏覽器。 版面配置範本可讓您輕鬆進行變更,然後套用到應用程式中的所有頁面。 若要深入了解,請參閱版面配置

電影清單檢視

不過,有一小部分「資料」:"Hello from our View Template!" 訊息是硬式編碼。 MVC 應用程式有一個 "V" (檢視)、一個 "C" (控制器),但還沒有 "M" (模型)。

將資料從控制器傳遞至檢視

回應傳入的 URL 要求時會叫用控制器動作。 控制器類別是撰寫處理傳入瀏覽器要求之程式碼的位置。 控制器會從資料來源擷取資料,並決定要將哪一種回應傳回瀏覽器中。 您可以從控制器使用檢視範本來產生並格式化瀏覽器的 HTML 回應。

控制器負責提供為了讓檢視範本呈現回應所需的資料。

檢視範本應該:

  • 執行商務邏輯
  • 直接與資料庫互動。

檢視範本應該只使用由控制器提供的資料。 維護此「關注點分離」有助於讓程式碼保持:

  • 乾淨。
  • 可測試。
  • 可維護。

目前,HelloWorldController 類別中的 Welcome 方法會採用 nameID 參數,然後將值直接輸出到瀏覽器。

與其讓控制器以字串方式呈現這個回應,不如變更控制器以改為使用檢視範本。 檢視範本會產生動態回應,這表示必須將適當的資料從控制器傳遞至檢視以產生回應。 若要執行此作業,可讓控制器將檢視範本需要的動態資料 (參數) 放置在 ViewData 字典。 然後,檢視範本就可以存取動態資料。

HelloWorldController.cs 中變更 Welcome 方法,將 MessageNumTimes 值新增至 ViewData 字典。

ViewData 字典是動態物件,這表示可以使用任何型別。 在新增任何項目之前,ViewData 物件沒有已定義的屬性。 MVC 模型繫結系統會自動將查詢字串中的具名參數 namenumTimes 對應至方法中的參數。 完整的 HelloWorldController

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 字典物件包含將傳遞至檢視的資料。

建立名為 Views/HelloWorld/Welcome.cshtml 的 Welcome 檢視範本。

您將在顯示 "Hello" NumTimesWelcome.cshtml 檢視範本中建立迴圈。 將 Views/HelloWorld/Welcome.cshtml 的內容取代成下列:

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

<h2>Welcome</h2>

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

儲存變更並瀏覽至下列 URL:

https://localhost:{PORT}/HelloWorld/Welcome?name=Rick&numtimes=4

資料是使用 MVC 模型繫結器從 URL 取得並傳遞至控制站。 控制器會將資料封裝成 ViewData 字典,並將該物件傳遞至檢視。 接著,檢視會以 HTML 將資料呈現到瀏覽器。

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

在前述範例中,使用了 ViewData 字典將資料從控制器傳遞至檢視。 稍後在教學課程中,會使用檢視模型將控制器中的資料傳遞至檢視。 優先使用檢視模型方法來傳遞資料,然後才是 ViewData 字典方法。

在下一個教學課程中,將會建立電影資料庫。