练习 - 添加新的 Razor 页面

已完成

在上一单元中,你获取了 Contoso Pizza 项目的源代码,然后对主页进行了一些简单的更改。 在本单元中,你将向项目添加新的 Razor 页面。

创建“披萨列表”页面

若要创建新的 Razor 页面,需使用 .NET CLI。

  1. 由于终端被 dotnet watch 命令阻止,因此请通过右键单击“资源管理器”中的 ContosoPizza 文件夹以打开另一个终端,然后选择“在集成终端中打开”。

  2. 在新的终端窗口中,输入以下命令:

    dotnet new page --name PizzaList --namespace ContosoPizza.Pages --output Pages
    

    上述命令:

    • ContosoPizza.Pages 命名空间中创建下面这两个文件:
      • PizzaList.cshtml - Razor 页面
      • PizzaList.cshtml.cs - 随附的 PageModel
    • 将两个文件存储在项目的 Pages 子目录中。
  3. 在 Pages/PizzaList.cshtml 中,在 @{ } 代码块中添加以下代码:

    ViewData["Title"] = "Pizza List 🍕";
    

    这会设置页面的 <title> 元素。

  4. 在文件末尾添加以下代码:

    <h1>Pizza List 🍕</h1>
    
    <!-- New Pizza form will go here -->
    
    <!-- List of pizzas will go here -->
    

    这会向页面添加一个标题,以及两个 HTML 注释占位符,用于稍后将添加的功能。

  5. 保存文件。 如果使用的是 GitHub Codespaces,则文件会自动保存。

  6. 返回到正在运行 dotnet watch 的终端,然后按 Ctrl+R 重新加载应用并检测新文件。

将“披萨列表”页面添加到导航菜单

这将是测试此页面的好时机,但无法在浏览器中访问此页面,因为尚未在导航菜单中链接它。 你现在将链接它。

  1. 打开 Pages/Shared/_Layout.cshtml。

  2. 在包含 navbar-nav 类的 <ul> 元素中(从第 21 行开始),请注意包含指向“主页”和“隐私”页面的链接的 <li> 元素。 将以下代码添加到列表末尾处包含“隐私”链接的 <li> 元素的后面:

    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="" asp-page="/PizzaList">Pizza List 🍕</a>
    </li>
    

    这会向导航菜单添加一个指向 PizzaList 页面的链接。

  3. 保存文件。 包含应用的浏览器选项卡会自动刷新以显示更改。 如果使用的是 GitHub Codespaces,则文件会自动保存,但需要手动刷新浏览器选项卡。

  4. 在导航菜单中选择“披萨列表 🍕”链接。 随即会显示“披萨列表”页面。

向依赖项注入容器注册 PizzaService 类

“披萨列表”页依赖于 PizzaService 对象来检索披萨列表。 你将使用依赖项注入向页面提供 PizzaService 对象。 首先,将 PizzaService 类注册到容器。

  1. 打开 Program.cs。

  2. 在将服务添加到容器的部分中,添加以下代码:

    builder.Services.AddScoped<PizzaService>();
    

    此代码向依赖项注入容器注册 PizzaService 类。 AddScoped 方法指示应为每个 HTTP 请求创建新的 PizzaService 对象。 现在可以将 PizzaService 注入到任何 Razor 页面。

  3. 保存文件。 如果使用的是 GitHub Codespaces,则文件会自动保存。

显示披萨列表

让我们来修改“披萨列表”页面的 PageModel 类,以从 PizzaService 对象检索披萨列表并将其存储在属性中。

  1. 打开 Pages/PizzaList.cshtml.cs。

  2. 将下列 using 语句添加到文件顶部:

    using ContosoPizza.Models;
    using ContosoPizza.Services;
    

    这些语句可导入你将在页面中使用的 PizzaPizzaService 类型。

  3. ContosoPizza.Pages 命名空间块中,将整个 PizzaListModel 类替换为以下代码:

    public class PizzaListModel : PageModel
    {
        private readonly PizzaService _service;
        public IList<Pizza> PizzaList { get;set; } = default!;
    
        public PizzaListModel(PizzaService service)
        {
            _service = service;
        }
    
        public void OnGet()
        {
            PizzaList = _service.GetPizzas();
        }
    }
    

    在上述代码中:

    • 已创建名为 _service 的专用只读 PizzaService。 此变量将保存对 PizzaService 对象的引用。
      • readonly 关键字指示在构造函数中设置 _service 变量的值之后无法对其进行更改。
    • 定义 PizzaList 属性以保存披萨列表。
      • IList<Pizza> 类型指示 PizzaList 属性将保存 Pizza 对象列表。
      • PizzaList 被初始化为 default!,以向编译器表明它稍后将被初始化,因此不需要进行 null 安全性检查。
    • 构造函数接受 PizzaService 对象。
      • 对象 PizzaService 通过依赖项注入提供。
    • 定义 OnGet 方法以从 PizzaService 对象中检索披萨列表并将其存储在 PizzaList 属性中。

    提示

    如果需要了解 null 安全方面的帮助,请参阅 C# 中的 null 安全

  4. 保存文件。 如果使用的是 GitHub Codespaces,则文件会自动保存。

  5. 返回到正在运行 dotnet watch 的终端,然后按 Ctrl+R 以重新加载具有已注册服务和 PizzaListModel 的新构造函数的应用。

显示披萨列表

现在,可在页面上访问披萨列表,接下来需要使用该列表在页面上显示披萨。

  1. 打开 Pages/PizzaList.cshtml。

  2. 使用下面的代码替换 <!-- List of pizzas will go here --> 注释:

    <table class="table mt-5">
        <thead>
            <tr>
                <th scope="col">Name</th>
                <th scope="col">Price</th>
                <th scope="col">Size</th>
                <th scope="col">Gluten Free</th>
                <th scope="col">Delete</th>
            </tr>
        </thead>
        <tbody>
        @foreach (var pizza in Model.PizzaList)
        {
            <tr>
                <td>@pizza.Name</td>
                <td>@($"{pizza.Price:C}")</td>
                <td>@pizza.Size</td>
                <td>@(pizza.IsGlutenFree ? "✔️" : string.Empty)</td>
                <td>
                    <form method="post" asp-page-handler="Delete" asp-route-id="@pizza.Id">
                        <button class="btn btn-danger">Delete</button>
                    </form>
                </td>
            </tr>
        }
        </tbody>
    </table>
    

    在上述代码中:

    • 已创建 <table> 元素来显示披萨列表。
    • 已创建 <thead> 元素来保存表格标题。
    • <tbody> 中的 @foreach 语句循环访问披萨列表。
      • Model 属性引用在代码隐藏文件中创建的 PizzaListModel 对象。
      • PizzaList 属性引用在代码隐藏文件中定义的 PizzaList 属性。
    • @foreach 语句的每个迭代都会创建一个 <tr> 元素来保存披萨数据:
      • Razor 语法用于显示 <td> 元素中的披萨数据。 此语法用于显示存储在 pizza 变量中的 Pizza 对象的属性。
      • Price 是使用 C# 字符串内插进行格式设置的。
      • 三元表达式用于显示 IsGlutenFree 属性的值(“✔️”或空白单元格)。
      • 已创建表单来删除披萨。
        • asp-page-handler 属性指示应将表单提交到代码隐藏文件中的 Delete 处理程序。 你将在后面的单元中创建该处理程序。
        • asp-route-id 属性指示应将 Pizza 对象的 Id 属性传递给 Delete 处理程序。
  3. 保存文件。 在浏览器中,“披萨列表”页面会刷新以显示披萨列表。 如果使用的是 GitHub Codespaces,则文件会自动保存,但需要手动刷新浏览器选项卡。

包含工作列表的“披萨列表”页面的屏幕截图。

做得很好! 你已创建一个显示披萨列表的 Razor 页面。 在下一单元中,你将了解标记帮助程序和页面处理程序。