练习 - 使用路由参数改进应用导航

已完成

Blazor 路由参数允许组件访问在 URL 中传递的数据。 路由参数将允许应用按订单的 OrderId 访问特定订单。

客户希望能够看到有关特定订单详细信息。 你将更新结帐页,使客户直接转到其已下达的订单。 然后,你将更新订单页,让用户可以跟踪任何当前未处理的订单。

在此练习中,你将添加一个利用路由参数的新订单详情页。 你将了解如何向参数添加约束以检查正确的数据类型。

创建订单详情页

  1. 在 Visual Studio Code 的菜单上,选择“文件”>“新建文本文件”。

  2. 选择 ASP.NET Razor 作为语言。

  3. 使用此代码创建订单详情页组件:

    @page "/myorders/{orderId}"
    @inject NavigationManager NavigationManager
    @inject HttpClient HttpClient
    
    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <NavLink href="" class="nav-tab" Match="NavLinkMatch.All">
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </NavLink>
    
        <NavLink href="myorders" class="nav-tab">
            <img src="img/bike.svg" />
            <div>My Orders</div>
        </NavLink>
    
    </div>
    
    <div class="main">
        @if (invalidOrder)
        {
            <h2>Order not found</h2>
            <p>We're sorry but this order no longer exists.</p>
        }
        else if (orderWithStatus == null)
        {
            <div class="track-order">
                <div class="track-order-title">
                    <h2>
                      <text>Loading...</text>
                    </h2>
                    <p class="ml-auto mb-0">
                        ...
                    </p>
                </div>
            </div>
        }
        else
        {
            <div class="track-order">
                <div class="track-order-title">
                    <h2>
                        Order placed @orderWithStatus.Order.CreatedTime.ToLongDateString()
                    </h2>
                    <p class="ml-auto mb-0">
                        Status: <strong>@orderWithStatus.StatusText</strong>
                    </p>
                </div>
                <div class="track-order-body">
                    <div class="track-order-details">
                      @foreach (var pizza in orderWithStatus.Order.Pizzas)
                      {
                          <p>
                              <strong>
                                  @(pizza.Size)"
                                  @pizza.Special.Name
                                  (£@pizza.GetFormattedTotalPrice())
                              </strong>
                          </p>
                      }
                    </div>
                </div>
            </div>
        }
    </div>
    
    @code {
        [Parameter] public int OrderId { get; set; }
    
        OrderWithStatus orderWithStatus;
        bool invalidOrder = false;
    
        protected override async Task OnParametersSetAsync()
        {
          try
          {
              orderWithStatus = await HttpClient.GetFromJsonAsync<OrderWithStatus>(
                  $"{NavigationManager.BaseUri}orders/{OrderId}");
          }
          catch (Exception ex)
          {
              invalidOrder = true;
              Console.Error.WriteLine(ex);
          }
        }
    }
    
    

    此页将类似于 MyOrders 组件。 我们将调用 OrderController,但这次要请求特定订单。 我们需要与 OrderId 匹配的订单。 让我们添加用于处理此请求的代码。

  4. 选择 Ctrl+S 保存所做更改。

  5. 对于文件名,请使用“OrderDetail.razor”。 请确保将文件保存在 Pages 目录中。

  6. 在文件资源管理器中,选择“OrderController.cs”。

  7. PlaceOrder 方法下,添加新方法以返回有状态的订单。

    [HttpGet("{orderId}")]
    public async Task<ActionResult<OrderWithStatus>> GetOrderWithStatus(int orderId)
    {
        var order = await _db.Orders
            .Where(o => o.OrderId == orderId)
            .Include(o => o.Pizzas).ThenInclude(p => p.Special)
            .Include(o => o.Pizzas).ThenInclude(p => p.Toppings).ThenInclude(t => t.Topping)
            .SingleOrDefaultAsync();
    
        if (order == null)
        {
            return NotFound();
        }
    
        return OrderWithStatus.FromOrder(order);
    }
    

    此代码使 Order 控制器能够响应 URL 中具有 orderId 的 HTTP 请求。 然后,该方法使用此 ID 查询数据库,如果找到订单,则返回 OrderWithStatus 对象。

    让我们在客户结账时使用此新页面。需要更新 Checkout.razor 组件。

  8. 在文件资源管理器中,展开“页面”。 然后选择“Checkout.razor”。

  9. 将对 NavigationManager.NavigateTo("/myorders") 的调用改为使用已下订单的订单 ID。

    NavigationManager.NavigateTo($"myorders/{newOrderId}");
    

    现有代码已捕获 newOrderId 作为对下订单的响应。 现在可以使用它直接转到该订单。

将路由参数限制为正确的数据类型

应用应仅响应具有数字订单 ID 的请求,例如 (http://localhost:5000/myorders/6)。 如果有人尝试使用非数字订单,不会阻止这种行为。 让我们改变这点。

  1. 在文件资源管理器中,展开“页面”。 然后选择“OrderDetail.razor”。

  2. 更改路由参数,使组件仅接受整数。

    @page "/myorders/{orderId:int}"
    
  3. 现在,如果有人尝试转到 (http://localhost:5000/myorders/non-number),Blazor 路由将找不到 URL 的匹配项,并返回“未找到页面”。

    “未找到页面”屏幕的屏幕截图。

  4. 在 Visual Studio Code 中,选择 F5。 在“运行”菜单上,选择“开始调试”。

    屏幕截图显示了单个订单的订单详情页。

    浏览应用,下订单并结帐。 将转到订单详情屏幕,你可以在这里看到订单的状态。

  5. 尝试不同的订单 ID。 如果使用不是有效订单号的整数,将显示“未找到订单”消息。

    显示“未找到订单”消息的屏幕截图。

    如果使用非整数订单 ID,将看到“未找到页面”。 更重要的是,应用不会有未经处理的异常。

  6. 选择 Shift + F5 以停止应用。

更新订单页

目前,“我的订单”页包含查看更多详细信息的链接,但 URL 错误。

  1. 在文件资源管理器中,展开“页面”。 然后选择“MyOrders.razor”。

  2. <a href="myorders/" class="btn btn-success"> 元素替换为以下代码:

    <a href="myorders/@item.Order.OrderId" class="btn btn-success">
    

可以在此练习中下达最后一份披萨订单,测试其运行情况。 然后选择“我的订单”,并打开“跟踪 >”链接。