Übung: Ändern der Navigation in Ihrer Blazor-App mithilfe der @page-Anweisung
Blazor verfügt über ein Navigationszustand-Hilfsprogramm, mit dem C#-Code die URIs einer 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
Hinweis
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 6.0 SDK verwendet. Stellen Sie sicher, dass .NET 6.0 installiert ist, indem Sie in Ihrem bevorzugten Terminal den folgenden Befehl ausführen:
dotnet --list-sdks
Daraufhin wird eine Ausgabe angezeigt, die in etwa wie folgt aussieht:
3.1.100 [C:\program files\dotnet\sdk]
5.0.100 [C:\program files\dotnet\sdk]
6.0.100 [C:\program files\dotnet\sdk]
Stellen Sie sicher, dass eine Version aufgeführt wird, die mit 6
beginnt. Wenn keine solche Version aufgeführt wird oder der Befehl nicht gefunden wurde, installieren Sie das neueste .NET 6.0 SDK.
Wenn Sie noch nie eine Blazor-Anwendung erstellt haben, 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 BlazingPizza
Wä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 „404 nicht gefunden“ wird angezeigt, da noch keine Check-Out-Seite 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
OrderState
gespeicherten 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>
Auf dieser Seite wäre es gut, den Link für die Kunden hervorzuheben. Das Team hat bereits eine
active
-CSS-Klasse erstellt. Fügen Sie alsoactive
demclass
-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 setzen Sie die Bestellung auf der Check-Out-Seite fort. 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 im Menü von Visual Studio Code Datei>Neue Textdatei aus.
Wählen Sie die Sprache C# aus, und geben Sie diesen Code ein:
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.
Verwenden Sie als Dateinamen OrderController.cs. Stellen Sie sicher, dass Sie die Datei im gleichen Verzeichnis wie OrderState.cs speichern.
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-Klasseactive
hinzufü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
active
wird 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,
NavigationManager
so zu ändern, dass nach einer Bestellung eine Weiterleitung auf die Seitemyorders
erfolgt. 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/myorders
anNavigationManager.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.