Esercizio: Modificare lo spostamento nell'app Blazor usando la direttiva @page
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 aggiungere all'app il completamento della transazione e altre pagine correlate agli ordini.
In questo esercizio vengono aggiunti all'app una nuova pagina di completamento della transazione e un riquadro di spostamento superiore, 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.
Aprire Visual Studio Code.
Aprire il terminale integrato da Visual Studio Code selezionando Visualizza. Quindi nel menu principale selezionare Terminale.
Nel terminale passare alla posizione in cui si vuole creare il progetto.
Clonare l'app da GitHub.
git clone https://github.com/MicrosoftDocs/mslearn-blazor-navigation.git BlazingPizza
Selezionare File e quindi Apri cartella.
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.
Eseguire l'app per controllare che tutto funzioni correttamente.
In Visual Studio Code selezionare F5. In alternativa, selezionare Avvia debug nel menu Esegui.
Configurare alcune pizze e aggiungerle all'ordine. Nella parte inferiore della pagina selezionare Order > (Ordina). Viene visualizzato il messaggio "404 non trovato" predefinito perché non è ancora presente una pagina di completamento della transazione.
Per arrestare l'app, premere MAIUSC + F5.
Aggiungere una pagina di completamento della transazione
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 visualizzano i clienti se tentano di passare a una pagina che non esiste.In Esplora file espandere Pagine, fare clic con il pulsante destro del mouse sulla cartella e selezionare Nuovo file.
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 primodiv
è il nuovo menu di spostamento dell'intestazione dell'app. Aggiungerlo alla pagina dell'indice.In Esplora file espandere Pagine e quindi selezionare index.razor.
Sopra la classe
<div class="main">
, aggiungere il codice HTMLtop-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 quindiactive
all'attributoclass
che contiene già lo stilenav-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>
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. Vengono visualizzati un elenco delle pizze e l'indicatore attivo mancante dal menu.
Per arrestare l'app, premere MAIUSC + F5.
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.
In Esplora file espandere Pagine e selezionare Checkout.razor.
Modificare l'elemento button con una chiamata al metodo
PlaceOrder
. Aggiungere gli attributi@onclick
edisabled
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.
Nel blocco
@code
aggiungere questo codice sotto il codiceOrder 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 e lo aggiunge a pizza.db, cancella l'ordine e usa
NavigationManager
per reindirizzare i clienti alla home page.È necessario aggiungere codice per gestire l'ordine. Aggiungere una classe OrderController per questa attività. Se si esamina PizzaStoreContext.cs, è 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
In Esplora file selezionare PizzaStoreContext.cs.
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.
In Visual Studio Code scegliere File>Nuovo file di testo dal menu.
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}.Salvare le modifiche con CTRL+S.
Per il nome file, usare OrderController.cs. Assicurarsi di salvare il file nella stessa directory di OrderState.cs.
In Esplora file selezionare OrderState.cs.
Nella parte inferiore della classe del metodo
RemoveConfiguredPizza
modificareResetOrder()
per reimpostare l'ordine:public void ResetOrder() { Order = new Order(); }
Testare la funzionalità di completamento della transazione
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 completare la transazione, viene 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.
Per arrestare l'app, premere MAIUSC + F5.
In Esplora file eliminare il file pizza.db.
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 viene reindirizzati alla home page dove è possibile notare che l'ordine è ora vuoto.
Per arrestare l'app, premere MAIUSC + F5.
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
In Esplora file espandere Pagine, fare clic con il pulsante destro del mouse sulla cartella e selezionare Nuovo file.
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 > </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 cssactive
. Aggiornare tutti i riquadri di spostamento in modo che venga usato un componente NavLink.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.L'ultimo passaggio consiste nel modificare
NavigationManager
per reindirizzare alla paginamyorders
dopo l'inserimento di un ordine. In Esplora file espandere Pagine e selezionare Checkout.razor.Modificare il metodo
PlaceOrder
per reindirizzare alla pagina corretta passando/myorders
aNavigationManager.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"); }
In Visual Studio Code selezionare F5. In alternativa, selezionare Avvia debug nel menu Esegui.
È possibile ordinare le pizze e quindi visualizzare gli ordini attualmente presenti nel database.
Arrestare l'app premendo MAIUSC + F5.