Übung: Ändern der Navigation in Ihrer Blazor-App mithilfe der @page-Anweisung
Blazor verfügt über ein Navigationsstatushilfsprogramm, mit dem C#-Code einen URI in Ihrer App verwalten kann. Es gibt auch eine NavLink-Komponente, die ein Drop-In-Ersatz für das <a>-Element ist. Eines der NavLink-Features ist das Hinzufügen einer aktiven Klasse zu HTML-Links für die Menüs einer App.
Ihr Team hat mit der Blazing Pizza-App begonnen und Blazor-Komponenten zur Darstellung von Pizzas und Bestellungen erstellt. Die App muss jetzt Check-Out-Seiten und andere bestellbezogene Seiten hinzufügen.
In dieser Übung fügen Sie eine neue Check-Out-Seite hinzu, ergänzen die App um eine obere Navigationsleiste und verwenden dann eine NavLink-Komponente von Blazor, um Ihren Code zu verbessern.
Klonen der vorhandenen App Ihres Teams
Note
In diesem Modul werden die .NET-CLI (Befehlszeilenschnittstelle) und Visual Studio Code für die lokale Entwicklung verwendet. Nach Abschluss dieses Moduls können Sie die Konzepte mithilfe von Visual Studio (Windows) oder Visual Studio für Mac (macOS) anwenden. Verwenden Sie für die weitere Entwicklung Visual Studio Code für Windows, Linux und macOS.
In diesem Modul wird das .NET 9.0 SDK verwendet. Stellen Sie sicher, dass .NET 9.0 installiert ist, indem Sie in Ihrem bevorzugten Befehlsterminal den folgenden Befehl ausführen:
dotnet --list-sdks
Die daraufhin angezeigte Ausgabe sieht in etwa wie im folgenden Beispiel aus:
8.0.100 [C:\Program Files\dotnet\sdk]
9.0.100 [C:\Program Files\dotnet\sdk]
Stellen Sie sicher, dass eine Version aufgeführt wird, die mit 9 beginnt. Wenn nichts aufgeführt ist oder der Befehl nicht gefunden wurde, installieren Sie das neueste .NET 9.0 SDK.
Wenn Sie Ihre erste Blazor-App erstellen, befolgen Sie die Setupanweisungen für Blazor , um die richtige Version von .NET zu installieren und zu überprüfen, ob Ihr Computer ordnungsgemäß eingerichtet ist. Halten Sie beim Schritt Erstellen Ihrer App an.
Öffnen Sie Visual Studio Code.
Öffnen Sie das integrierte Terminal über Visual Studio Code, indem Sie im Hauptmenü Ansicht auswählen. Wählen Sie dann im Hauptmenü Terminal aus.
Navigieren Sie im Terminal zu dem Speicherort, an dem das Projekt erstellt werden soll.
Klonen Sie die App aus GitHub.
git clone https://github.com/MicrosoftDocs/mslearn-blazor-navigation.git BlazingPizzaWählen Sie Datei und dann Ordner öffnen aus.
Navigieren Sie im Dialogfeld Öffnen zum Ordner BlazingPizza, und wählen Sie Ordner auswählen aus.
Visual Studio Code weist Sie möglicherweise auf nicht aufgelöste Abhängigkeiten hin. Wählen Sie "Wiederherstellen" aus.
Führen Sie die App aus, um zu überprüfen, ob alles ordnungsgemäß funktioniert.
Drücken Sie in Visual Studio Code F5. Wählen Sie alternativ Debuggen starten im Menü Ausführen aus.
Stellen Sie einige Pizzas zusammen, und fügen Sie diese Ihrer Bestellung hinzu. Klicken Sie unten auf der Seite auf Order > (Bestellen). Die Standardmeldung "Leider gibt es an dieser Adresse nichts." wird angezeigt, da noch keine Auscheckseite vorhanden ist.
Drücken Sie UMSCHALT + F5, um die App zu beenden.
Hinzufügen einer Check-Out-Seite
Wählen Sie in Visual Studio Code im Datei-Explorer die Datei App.razor aus.
<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>Der
<NotFound>-Codeblock wird Kunden angezeigt, wenn sie versuchen, eine nicht vorhandene Seite aufzurufen.Erweitern Sie im Datei-Explorer den Ordner Pages, klicken Sie mit der rechten Maustaste auf den Ordner, und wählen Sie Neue Datei aus.
Benennen Sie die neue Datei Checkout.razor. Geben Sie in der Datei den folgenden Code ein:
@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; }Diese Seite baut auf der aktuellen App auf und nutzt den in
OrderStategespeicherten App-Zustand. Das erstediv-Element ist die neue Headernavigation der App. Jetzt fügen wir sie der Indexseite hinzu.Erweitern Sie im Datei-Explorer den Ordner Pages, und wählen Sie dann index.razor aus.
Fügen Sie oberhalb der
<div class="main">-Klasse dentop-bar-HTML-Code hinzu.<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>Wenn wir auf dieser Seite sind, wäre es schön, den Kunden durch Hervorheben des Links etwas zu zeigen. Das Team hat bereits eine
active-CSS-Klasse erstellt. Fügen Sie alsoactivedemclass-Attribut hinzu, das bereits dienav-tab-Formatvorlage enthält.<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>Drücken Sie in Visual Studio Code F5. Wählen Sie alternativ Debuggen starten im Menü Ausführen aus.
Die App verfügt jetzt oben über eine ansprechende Menüleiste mit Unternehmenslogo. Fügen Sie einige Pizzas hinzu, und wählen Sie die Schaltfläche " Bestellung " aus, um zur Auscheckseite zu gelangen. Die Pizzas werden aufgelistet, aber der Aktiv-Indikator fehlt im Menü.
Drücken Sie UMSCHALT + F5, um die App zu beenden.
Kunden das Bestellen erlauben
Derzeit können die Kunden keine Bestellungen über die Check-Out-Seite aufgeben. Die Logik der App muss die Bestellung speichern, die an die Küche gesendet werden soll. Nachdem die Bestellung aufgegeben wurde, leiten Sie die Kunden zurück zur Homepage.
Erweitern Sie im Datei-Explorer den Ordner Pages, und wählen Sie dann Checkout.razor aus.
Ändern Sie das Schaltflächenelement mit einem Aufruf einer
PlaceOrder-Methode. Fügen Sie die@onclick- unddisabled-Attribute wie gezeigt hinzu:<button class="checkout-button btn btn-warning" @onclick="PlaceOrder" disabled=@isSubmitting> Place order </button>Kunden sollen Bestellungen nicht doppelt aufgeben können. Deaktivieren Sie daher die Schaltfläche Place order (Bestellung aufgeben), bis die Bestellung verarbeitet wurde.
Fügen Sie im
@code-Block den folgenden Code unter dem CodeOrder Order => OrderState.Order;hinzu.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("/"); }Der vorangehende Code deaktiviert die Schaltfläche Bestellung aufgeben, stellt JSON-Code bereit und fügt ihn zu pizza.db hinzu, löscht die Bestellung und verwendet
NavigationManager, um Kunden zurück auf die Homepage zu leiten.Sie müssen Code hinzufügen, um die Bestellung zu verarbeiten. Fügen Sie eine OrderController-Klasse für diese Aufgabe hinzu. Wenn Sie die Datei PizzaStoreContext.cs betrachten, sehen Sie nur Entity Framework-Datenbankunterstützung für
PizzaSpecials. Korrigieren Sie dies zunächst.
Hinzufügen von Entity Framework-Unterstützung für Bestellungen und Pizzas
Wählen Sie im Datei-Explorer PizzaStoreContext.cs aus.
Ersetzen Sie die
PizzaStoreContext-Klasse durch diesen Code: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(); } }Dieser Code fügt Entity Framework-Unterstützung für die order- und pizza-Klassen der App hinzu.
Wählen Sie in Visual Studio Code im Menü "Neue Datei"> aus.
Geben Sie OrderController.cs als Dateinamen ein. Stellen Sie sicher, dass Sie die Datei im gleichen Verzeichnis wie OrderState.cs speichern.
Fügen Sie den folgenden Code hinzu:
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; } }Mit dem vorangehenden Code kann die App alle aktuellen Bestellungen abrufen und eine Bestellung aufgeben. Mit dem
[Route("orders")]-Attribut von Blazor kann diese Klasse eingehende HTTP-Anforderungen für /orders und /orders/{orderId} verarbeiten.Speichern Sie Ihre Änderungen mit STRG+S.
Wählen Sie im Datei-Explorer OrderState.cs aus.
Ändern Sie am Ende der Klasse unter der
RemoveConfiguredPizza-MethodeResetOrder(), um die Bestellung zurückzusetzen:public void ResetOrder() { Order = new Order(); }
Testen der Check-Out-Funktionalität
Drücken Sie in Visual Studio Code F5. Wählen Sie alternativ Debuggen starten im Menü Ausführen aus.
Die App sollte kompiliert werden, aber wenn Sie eine Bestellung erstellen und den Auftragsabschluss versuchen, wird ein Laufzeitfehler angezeigt. Dieser Fehler tritt auf, weil die SQLLite-Datenbank pizza.db erstellt wurde, bevor Bestellungen und Pizzas unterstützt wurden. Sie müssen die Datei löschen, damit eine neue Datenbank ordnungsgemäß erstellt werden kann.
Drücken Sie UMSCHALT + F5, um die App zu beenden.
Löschen Sie im Datei-Explorer die Datei pizza.db.
Drücken Sie F5. Wählen Sie alternativ Debuggen starten im Menü Ausführen aus.
Fügen Sie testweise Pizzas hinzu, und geben Sie über die Check-Out-Seite eine Bestellung auf. Sie werden zurück zur Homepage geleitet und Sie können sehen, dass die Bestellung jetzt leer ist.
Drücken Sie UMSCHALT + F5, um die App zu beenden.
Die App wird besser. Sie verfügen über eine Pizzakonfiguration und einen Check-Out-Vorgang. Kunden sollen den Status ihrer Pizzabestellung einsehen können, nachdem sie diese aufgegeben haben.
Hinzufügen einer Bestellseite
Erweitern Sie im Datei-Explorer den Ordner Pages, klicken Sie mit der rechten Maustaste auf den Ordner, und wählen Sie Neue Datei aus.
Benennen Sie die neue Datei MyOrders.razor. Geben Sie in der Datei den folgenden Code ein:
@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"); } }Die Navigation muss sich auf allen Seiten ändern. Fügen Sie deshalb einen Link zur neuen Seite My orders (Meine Bestellungen) ein. Öffnen Sie Checkout.razor und Index.razor, und ersetzen Sie die Navigation durch den folgenden Code:
<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>Durch die Verwendung von
<a>-Elementen können Sie manuell verwalten, welches die aktive Seite ist, indem Sie die CSS-Klasseactivehinzufügen. Aktualisieren wir die gesamte Navigation, um stattdessen eine NavLink-Komponente zu verwenden.Verwenden Sie auf allen drei Seiten mit Navigation (Index.razor, Checkout.razor und MyOrders.razor) den gleichen Blazor-Code für die Navigation:
<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>Die CSS-Klasse
activewird jetzt von der NavLink-Komponente automatisch zu Seiten hinzugefügt. Sie müssen nicht daran denken, dies auf jeder Seite vorzunehmen, auf der sich die Navigation befindet.Der letzte Schritt besteht darin,
NavigationManagerso zu ändern, dass nach einer Bestellung eine Weiterleitung auf die Seitemyorderserfolgt. Erweitern Sie im Datei-Explorer den Ordner Pages, und wählen Sie dann Checkout.razor aus.Ändern Sie die
PlaceOrder-Methode so, dass eine Weiterleitung zur richtigen Seite erfolgt, indem Sie/myordersanNavigationManager.NavigateTo()übergeben.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"); }Drücken Sie in Visual Studio Code F5. Wählen Sie alternativ Debuggen starten im Menü Ausführen aus.
Sie sollten in der Lage sein, einige Pizzas zu bestellen und dann die derzeit in der Datenbank enthaltenen Bestellungen anzuzeigen.
Beenden Sie die App, indem Sie UMSCHALT + F5 auswählen.