Esercizio: Usare i parametri di route per migliorare lo spostamento delle app

Completato

I parametri di route di Blazor consentono ai componenti di accedere ai dati passati nell'URL. I parametri di route consentono all’app di accedere a ordini specifici in base al loro valore di OrderId.

I clienti vogliono poter visualizzare altre informazioni su ordini specifici. Si decide quindi di aggiornare la pagina di completamento della transazione in modo da indirizzare direttamente i clienti agli ordini inseriti. Quindi, si vuole aggiornare la pagina degli ordini per consentire loro di tenere traccia di qualsiasi ordine attualmente aperto.

In questo esercizio si aggiungerà una nuova pagina dei dettagli dell'ordine in cui vengono usati parametri di route. Verrà quindi spiegato come aggiungere un vincolo al parametro per controllare il tipo di dati corretto.

Creare una pagina dei dettagli dell'ordine

  1. In Visual Studio Code scegliere File>Nuovo file di testo dal menu.

  2. Selezionare ASP.NET Razor come linguaggio.

  3. Creare un componente della pagina dei dettagli dell'ordine con questo codice:

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

    Questa pagina è simile al componente MyOrders. Verrà effettuata una chiamata a OrderController, ma questa volta per richiedere un ordine specifico. Si vuole ottenere l'ordine corrispondente al valore di OrderId. Ora, è necessario aggiungere il codice per elaborare questa richiesta.

  4. Salvare le modifiche premendo CTRL+S.

  5. Come nome file usare OrderDetail.razor. Assicurarsi di salvare il file nella directory Pages.

  6. In Esplora file selezionare OrderController.cs.

  7. Nel metodo PlaceOrder aggiungere un nuovo metodo per restituire gli ordini con uno stato.

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

    Questo codice ha abilitato il controller Order per rispondere a una richiesta HTTP il cui URL include orderId. Il metodo usa quindi questo ID per eseguire una query sul database e, se viene trovato un ordine, restituire un oggetto OrderWithStatus.

    Questa nuova pagina verrà usata quando il cliente completa la transazione. È necessario aggiornare il componente Checkout.razor.

  8. In Esplora file espandere Pages. Selezionare quindi Checkout.razor.

  9. Modificare la chiamata alla seguente per usare l'ID ordine dell'ordine inserito.

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

    Il codice esistente acquisiva già newOrderId come risposta dall'inserimento dell'ordine. È ora possibile usarlo per passare direttamente a tale ordine.

Limitare il parametro di route al tipo di dati corretto

L'app deve rispondere solo alle richieste con ID ordine numerico, ad esempio (http://localhost:5000/myorders/6). Non c'è nulla che impedisca a un utente di provare a usare ordini non numerici. Si può cambiare.

  1. In Esplora file espandere Pages. Selezionare quindi OrderDetail.razor.

  2. Modificare il parametro di route in modo che il componente accetti solo numeri interi.

    @page "/myorders/{orderId:int}"
    
  3. Ora se un utente prova ad accedere a (http://localhost:5000/myorders/non-number), il routing Blazor non trova una corrispondenza per l'URL e restituisce il messaggio di pagina non trovata.

    Screenshot della schermata di pagina non trovata.

  4. In Visual Studio Code selezionare F5. In alternativa, selezionare Avvia debug nel menu Esegui.

    Screenshot che mostra la pagina dei dettagli per un singolo ordine.

    Esaminare l’app, l’ordine e il completamento della transazione. Viene visualizzata la schermata dell'ordine dettagliato in cui è indicato lo stato dell'ordine.

  5. Provare con ID ordine diversi. Se si usa un numero intero che non corrisponde a un ordine valido, viene visualizzato un messaggio Ordine non trovato.

    Screenshot che mostra il messaggio di ordine non trovato.

    Se si usano ID ordine non costituiti da numeri interi, viene visualizzato il messaggio di pagina non trovata. Tuttavia, la cosa più importante è che nell'app non si verifica un'eccezione non gestita.

  6. Per arrestare l'app, premere MAIUSC + F5.

Aggiornare la pagina degli ordini

Al momento, la pagina My Orders (Ordini personali) contiene collegamenti per visualizzare maggiori dettagli, ma l'URL non è corretto.

  1. In Esplora file espandere Pages. Selezionare quindi MyOrders.razor.

  2. Sostituire l'elemento <a href="myorders/" class="btn btn-success"> con il codice seguente:

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

È ora possibile testarne il funzionamento del codice effettuando l'ultimo ordine di pizze per questo esercizio. Selezionare quindi My Orders (Ordini personali) e seguire il collegamento Track > (Tieni traccia).