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. Con i parametri di route l'app può accedere a ordini specifici in base al valore di OrderId.

I clienti vogliono poter visualizzare altre informazioni su ordini specifici. Verrà quindi aggiornata la pagina di completamento della transazione in modo da visualizzare direttamente ai clienti gli ordini inseriti. Si aggiornerà quindi 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à illustrato 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 sarà 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. Verrà quindi aggiunto il codice per elaborare questa richiesta.

  4. Premere CTRL+S per salvare le modifiche.

  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 troverà una corrispondenza per l'URL e restituirà 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 app, ordine e completamento della transazione. Verrà 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 ID ordine valido, verrà visualizzato un messaggio Order not found (Ordine non trovato).

    Screenshot che mostra il messaggio di ordine non trovato.

    Se si usano ID ordine non costituiti da numeri interi, verrà visualizzato il messaggio di pagina non trovata. Più importante, nell'app non si verificherà un'eccezione non gestita.

  6. Selezionare MAIUSC + F5 per arrestare l'app.

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 effettuando l'ultimo ordine di pizze per questo esercizio. Selezionare quindi My Orders (Ordini personali) e seguire il collegamento Track > (Tieni traccia).