Esercizio: Modificare lo spostamento nell'app Blazor usando la direttiva @page

Completato

Blazor ha un helper dello stato di spostamento che consente al codice C# di gestire gli URI di un'app. È disponibile anche un componente NavLink che rappresenta una soluzione sostitutiva per l'elemento <a>. Una delle funzionalità di NavLink è costituita dall'aggiunta di una classe attiva ai collegamenti HTML per i menu dell'app.

Il team ha iniziato l'app Blazing Pizza e ha creato componenti Blazor per rappresentare le pizze e gli ordini. Ora è necessario compilare la pagina relativa al completamento della transazione e altre pagine correlate agli ordini.

In questo esercizio verranno aggiunti all'app una nuova pagina di completamento della transazione e un riquadro di spostamento superiore e quindi verrà usato un componente Blazor NavLink per migliorare il codice.

Clonare l'app esistente del team

Nota

In questo modulo vengono usati l'interfaccia della riga di comando di .NET e Visual Studio Code per lo sviluppo locale. Dopo aver completato il modulo, è possibile applicare i concetti usando Visual Studio (Windows) o Visual Studio per Mac (macOS). Per lo sviluppo continuo usare Visual Studio Code per Windows, Linux e macOS.

Questo modulo usa .NET 6.0 SDK. Assicurarsi che .NET 6.0 sia installato eseguendo il comando successivo nel terminale preferito:

dotnet --list-sdks

Verrà visualizzato un output simile al seguente:

3.1.100 [C:\program files\dotnet\sdk]
5.0.100 [C:\program files\dotnet\sdk]
6.0.100 [C:\program files\dotnet\sdk]

Assicurarsi che sia elencata una versione che inizia con 6. Se non viene elencata alcuna versione o se il comando non viene trovato, installare la versione più recente di .NET 6.0 SDK.

Se non è stata ancora creata un'app Blazor, seguire le istruzioni di installazione per Blazor per installare la versione corretta di .NET e verificare che il computer sia configurato correttamente. Fermarsi al passaggio Creare un'app.

  1. Aprire Visual Studio Code.

  2. Aprire il terminale integrato da Visual Studio Code selezionando Visualizza. Quindi nel menu principale selezionare Terminale.

  3. Nel terminale passare alla posizione in cui si vuole creare il progetto.

  4. Clonare l'app da GitHub.

    git clone https://github.com/MicrosoftDocs/mslearn-blazor-navigation.git BlazingPizza
    
  5. Selezionare File e quindi Apri cartella.

  6. Nella finestra di dialogo Apri passare alla cartella BlazingPizza e scegliere Seleziona cartella.

    Visual Studio Code potrebbe richiedere informazioni sulle dipendenze non risolte. Selezionare Ripristina.

  7. Eseguire l'app per controllare che tutto funzioni correttamente.

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

    Screenshot che mostra la versione clonata dell'app Blazing Pizza.

    Configurare alcune pizze e aggiungerle all'ordine. Nella parte inferiore della pagina selezionare Order > (Ordina). Verrà visualizzato il messaggio predefinito "404 non trovato" perché il team non ha ancora compilato una pagina di completamento della transazione.

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

Aggiungere una pagina di completamento della transazione

  1. In Esplora file in Visual Studio Code selezionare App.razor.

    <Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
        <Found Context="routeData">
            <RouteView RouteData="@routeData" />
        </Found>
        <NotFound>
            <LayoutView>
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
    

    Il blocco di codice <NotFound> è quello che i clienti visualizzeranno se tentano di passare a una pagina che non esiste.

  2. In Esplora file espandere Pagine, fare clic con il pulsante destro del mouse sulla cartella e selezionare Nuovo file.

  3. Denominare il nuovo file Checkout.razor. In questo file aggiungere il codice riportato di seguito:

    @page "/checkout"
    @inject OrderState OrderState
    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab">
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
    </div>
    
    <div class="main">
        <div class="checkout-cols">
            <div class="checkout-order-details">
                <h4>Review order</h4>
                @foreach (var pizza in Order.Pizzas)
                {
                    <p>
                        <strong>
                            @(pizza.Size)"
                            @pizza.Special.Name
                            (£@pizza.GetFormattedTotalPrice())
                        </strong>
                    </p>
                }
    
                <p>
                    <strong>
                        Total price:
                        £@Order.GetFormattedTotalPrice()
                    </strong>
                </p>
            </div>
        </div>
    
        <button class="checkout-button btn btn-warning">
            Place order
        </button>
    </div>
    
    @code {
        Order Order => OrderState.Order;
    }
    

    Questa pagina si basa sull'app corrente e usa lo stato dell'app salvato in OrderState. Il primo div è il nuovo menu di spostamento dell'intestazione dell'app. Aggiungerlo alla pagina dell'indice.

  4. In Esplora file espandere Pagine e quindi selezionare index.razor.

  5. Sopra la classe <div class="main">, aggiungere il codice HTML top-bar.

    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab" >
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
    </div>
    

    Sarebbe bello indicare ai clienti che si trovano in questa pagina evidenziando il collegamento. Il team ha già creato una classe CSS active. Aggiungere quindi active all'attributo class che contiene già lo stile nav-tab.

    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab active" >
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
    </div>
    
  6. In Visual Studio Code selezionare F5. In alternativa, selezionare Avvia debug nel menu Esegui.

    L'app ora ha una barra dei menu in alto di aspetto gradevole, che include il logo dell'azienda. Aggiungere alcune pizze e proseguire nell'ordine fino alla pagina di completamento della transazione. Verranno visualizzate le pizze elencate e l'indicatore attivo mancante dal menu.

    Screenshot che mostra la pagina di checkout con alcune pizze.

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

Consentire ai clienti di inserire un ordine

Al momento, la pagina di completamento della transazione non consente ai clienti di effettuare gli ordini. La logica dell'app deve archiviare l'ordine da inviare alla cucina. Dopo l'invio dell'ordine, è necessario reindirizzare i clienti alla home page.

  1. In Esplora file espandere Pagine e selezionare Checkout.razor.

  2. Modificare l'elemento button in modo da chiamare un metodo PlaceOrder. Aggiungere gli attributi @onclick e disabled come illustrato:

    <button class="checkout-button btn btn-warning" @onclick="PlaceOrder" disabled=@isSubmitting>
      Place order
    </button>
    

    Per evitare che i clienti inviino ordini duplicati, si disabilita il pulsante Place order fino a quando l'ordine non viene elaborato.

  3. Nel blocco @code aggiungere questo codice sotto il codice Order Order => OrderState.Order;.

    bool isSubmitting;
    
    async Task PlaceOrder()
    {
        isSubmitting = true;
        var response = await HttpClient.PostAsJsonAsync(NavigationManager.BaseUri + "orders", OrderState.Order);
        var newOrderId= await response.Content.ReadFromJsonAsync<int>();
        OrderState.ResetOrder();
        NavigationManager.NavigateTo("/");
    }
    

    Il codice precedente disabilita il pulsante Place order (Inserisci ordine), pubblica JSON che verrà aggiunto a pizza.db, cancella l'ordine e usa NavigationManager per reindirizzare i clienti alla home page.

    È necessario aggiungere codice per gestire l'ordine. Per questa attività verrà aggiunta una classe OrderController. Se si esamina PizzaStoreContext.cs, si noterà che è disponibile solo il supporto del database Entity Framework per PizzaSpecials. Risolvere per prima cosa questo problema.

Aggiungere il supporto di Entity Framework per gli ordini e le pizze

  1. In Esplora file selezionare PizzaStoreContext.cs.

  2. Sostituire la classe PizzaStoreContext con il codice seguente:

      public class PizzaStoreContext : DbContext
      {
            public PizzaStoreContext(
                DbContextOptions options) : base(options)
            {
            }
    
            public DbSet<Order> Orders { get; set; }
    
            public DbSet<Pizza> Pizzas { get; set; }
    
            public DbSet<PizzaSpecial> Specials { get; set; }
    
            public DbSet<Topping> Toppings { get; set; }
    
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
    
                // Configuring a many-to-many special -> topping relationship that is friendly for serialization
                modelBuilder.Entity<PizzaTopping>().HasKey(pst => new { pst.PizzaId, pst.ToppingId });
                modelBuilder.Entity<PizzaTopping>().HasOne<Pizza>().WithMany(ps => ps.Toppings);
                modelBuilder.Entity<PizzaTopping>().HasOne(pst => pst.Topping).WithMany();
            }
    
      }
    

    Questo codice aggiunge il supporto di Entity Framework per le classi di ordini e pizze dell'app.

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

  4. Selezionare il linguaggio C# e immettere il codice seguente:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    
    namespace BlazingPizza;
    
    [Route("orders")]
    [ApiController]
    public class OrdersController : Controller
    {
        private readonly PizzaStoreContext _db;
    
        public OrdersController(PizzaStoreContext db)
        {
            _db = db;
        }
    
        [HttpGet]
        public async Task<ActionResult<List<OrderWithStatus>>> GetOrders()
        {
            var orders = await _db.Orders
     	    .Include(o => o.Pizzas).ThenInclude(p => p.Special)
     	    .Include(o => o.Pizzas).ThenInclude(p => p.Toppings).ThenInclude(t => t.Topping)
     	    .OrderByDescending(o => o.CreatedTime)
     	    .ToListAsync();
    
            return orders.Select(o => OrderWithStatus.FromOrder(o)).ToList();
        }
    
        [HttpPost]
        public async Task<ActionResult<int>> PlaceOrder(Order order)
        {
            order.CreatedTime = DateTime.Now;
    
            // Enforce existence of Pizza.SpecialId and Topping.ToppingId
            // in the database - prevent the submitter from making up
            // new specials and toppings
            foreach (var pizza in order.Pizzas)
            {
                pizza.SpecialId = pizza.Special.Id;
                pizza.Special = null;
            }
    
            _db.Orders.Attach(order);
            await _db.SaveChangesAsync();
    
            return order.OrderId;
        }
    }
    

    Il codice precedente consente all'app di ottenere tutti gli ordini correnti e inserire un ordine. L'attributo Blazor [Route("orders")] consente a questa classe di gestire le richieste HTTP in ingresso per /orders e /orders/{orderId}.

  5. Salvare le modifiche con CTRL+S.

  6. Per il nome file, usare OrderController.cs. Assicurarsi di salvare il file nella stessa directory di OrderState.cs.

  7. In Esplora file selezionare OrderState.cs.

  8. Nella parte inferiore della classe del metodo RemoveConfiguredPizza modificare ResetOrder() per reimpostare l'ordine:

    public void ResetOrder()
    {
        Order = new Order();
    }
    

Testare la funzionalità di completamento della transazione

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

    L'app dovrebbe essere compilata, ma se si crea un ordine e si tenta di eseguire il checkout, verrà visualizzato un errore di runtime. L'errore si verifica perché il database SQLLite pizza.db è stato creato prima del supporto per ordini e pizze. È necessario eliminare il file in modo che sia possibile creare correttamente un nuovo database.

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

  3. In Esplora file eliminare il file pizza.db.

  4. Selezionare F5. In alternativa, selezionare Avvia debug nel menu Esegui.

    Fare una prova aggiungendo alcune pizze, accedere alla pagina di completamento della transazione e inserire un ordine. Si verrà reindirizzati alla home page e si noterà che l'ordine è ora vuoto.

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

L'app sta migliorando. Sono state configurate le pizze e la pagina di completamento della transazione. Ora si vuole consentire ai clienti di visualizzare lo stato del loro ordine dopo averlo inserito.

Aggiungere una pagina degli ordini

  1. In Esplora file espandere Pagine, fare clic con il pulsante destro del mouse sulla cartella e selezionare Nuovo file.

  2. Denominare il nuovo file MyOrders.razor. In questo file aggiungere il codice riportato di seguito:

    @page "/myorders"
    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab">
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
        <a href="myorders" class="nav-tab active">
            <img src="img/bike.svg" />
            <div>My Orders</div>
        </a>
    </div>
    
    <div class="main">
        @if (ordersWithStatus == null)
        {
            <text>Loading...</text>
        }
        else if (!ordersWithStatus.Any())
        {
            <h2>No orders placed</h2>
            <a class="btn btn-success" href="">Order some pizza</a>
        }
        else
        {
            <div class="list-group orders-list">
                @foreach (var item in ordersWithStatus)
                {
                    <div class="list-group-item">
                        <div class="col">
                            <h5>@item.Order.CreatedTime.ToLongDateString()</h5>
                            Items:
                            <strong>@item.Order.Pizzas.Count()</strong>;
                            Total price:
                            <strong>£@item.Order.GetFormattedTotalPrice()</strong>
                        </div>
                        <div class="col">
                            Status: <strong>@item.StatusText</strong>
                        </div>
                        @if (@item.StatusText != "Delivered")
                        {
                            <div class="col flex-grow-0">
                                <a href="myorders/" class="btn btn-success">
                                    Track &gt;
                                </a>
                            </div>
                        }
                    </div>
                }
            </div>
        }
    </div>
    
    @code {
        List<OrderWithStatus> ordersWithStatus = new List<OrderWithStatus>();
    
        protected override async Task OnParametersSetAsync()
        {
          ordersWithStatus = await HttpClient.GetFromJsonAsync<List<OrderWithStatus>>(
              $"{NavigationManager.BaseUri}orders");
        }
    }
    

    È necessario che il riquadro di spostamento cambi in tutte le pagine in modo da includere un collegamento alla nuova pagina My orders (I miei ordini). Aprire Checkout.razor e Index.razor e sostituire il riquadro di spostamento con il codice seguente:

    <div class="top-bar">
        <a class="logo" href="">
            <img src="img/logo.svg" />
        </a>
    
        <a href="" class="nav-tab active" >
            <img src="img/pizza-slice.svg" />
            <div>Get Pizza</div>
        </a>
    
        <a href="myorders" class="nav-tab" >
            <img src="img/bike.svg" />
            <div>My orders</div>
        </a>
    
    </div>
    

    Usando gli elementi <a>, è possibile gestire manualmente la pagina attiva aggiungendo la classe css active. Aggiornare tutti i riquadri di spostamento in modo che venga usato un componente NavLink.

  3. In tutte e tre le pagine con riquadro di spostamento (Index.razor, Checkout.razor e MyOrders.razor) usare lo stesso codice Blazor per lo spostamento:

    <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>
    

    La classe css active viene ora aggiunta automaticamente alle pagine dal componente NavLink. Non è necessario ricordare di farlo in ogni pagina in cui è presente il riquadro di spostamento.

  4. L'ultimo passaggio consiste nel modificare NavigationManager per reindirizzare alla pagina myorders dopo l'inserimento di un ordine. In Esplora file espandere Pagine e selezionare Checkout.razor.

  5. Modificare il metodo PlaceOrder per reindirizzare alla pagina corretta passando /myorders a NavigationManager.NavigateTo():

    async Task PlaceOrder()
    {
        isSubmitting = true;
        var response = await HttpClient.PostAsJsonAsync($"{NavigationManager.BaseUri}orders", OrderState.Order);
        var newOrderId = await response.Content.ReadFromJsonAsync<int>();
        OrderState.ResetOrder();
        NavigationManager.NavigateTo("/myorders");
    } 
    
  6. In Visual Studio Code selezionare F5. In alternativa, selezionare Avvia debug nel menu Esegui.

    Screenshot che mostra la pagina dell'ordine.

    È possibile ordinare le pizze e quindi visualizzare gli ordini attualmente presenti nel database.

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