Övning – Ändra navigeringen i din Blazor-app med hjälp av @page-direktivet

Slutförd

Blazor har en hjälp för navigeringstillstånd som hjälper C#-kod att hantera en URI i din app. Det finns också en NavLink-komponent som är en drop-in ersättning för elementet <a> . En av NavLinks funktioner är att lägga till en aktiv klass i HTML-länkar för en apps menyer.

Ditt team började med Blazing Pizza-appen och byggde Blazor-komponenter för att representera pizzor och beställningar. Nu måste appen lägga till utcheckning och andra orderrelaterade sidor.

I den här övningen lägger du till en ny utcheckningssida, lägger till en övre navigering i appen och använder sedan en Blazor NavLink-komponent för att förbättra koden.

Klona teamets befintliga app

Note

I den här modulen används .NET-kommandoradsgränssnittet (CLI) och Visual Studio Code för lokal utveckling. När du har slutfört den här modulen kan du använda begreppen med hjälp av Visual Studio (Windows) eller Visual Studio för Mac (macOS). För fortsatt utveckling använder du Visual Studio Code för Windows, Linux och macOS.

I den här modulen används .NET 9.0 SDK. Kontrollera att du har .NET 9.0 installerat genom att köra följande kommando i önskad kommandoterminal:

dotnet --list-sdks

Utdata som liknar följande exempel visas:

8.0.100 [C:\Program Files\dotnet\sdk]
9.0.100 [C:\Program Files\dotnet\sdk]

Kontrollera att en version som börjar med 9 visas. Om inget visas eller om kommandot inte hittas installerar du den senaste .NET 9.0 SDK:t.

Om du skapar din första Blazor-app följer du installationsanvisningarna för Blazor för att installera rätt version av .NET och kontrollera att datorn är korrekt konfigurerad. Stanna vid steget Skapa din app .

  1. Öppna Visual Studio Code.

  2. Öppna den integrerade terminalen från Visual Studio Code genom att välja Visa. Välj sedan Terminal på huvudmenyn.

  3. I terminalen går du till den plats där du vill att projektet ska skapas.

  4. Klona appen från GitHub.

    git clone https://github.com/MicrosoftDocs/mslearn-blazor-navigation.git BlazingPizza
    
  5. Välj Arkiv och välj sedan Öppna mapp.

  6. I dialogrutan Öppna går du till mappen BlazingPizza och väljer Välj mapp.

    Visual Studio Code kan fråga dig om olösta beroenden. Välj Återställ.

  7. Kör appen för att kontrollera att allt fungerar korrekt.

  8. I Visual Studio Code väljer du F5. Eller på menyn Kör väljer du Starta felsökning.

    Skärmbild som visar den klonade versionen av Blazing Pizza-appen.

    Konfigurera några pizzor och lägg till dem i din beställning. Välj Order > längst ned på sidan. Standardmeddelandet "Det finns inget på den här adressen." visas eftersom det inte finns någon utcheckningssida ännu.

  9. Om du vill stoppa appen väljer du Skift + F5.

Lägg till en utcheckningssida

  1. I Visual Studio Code går du till utforskaren och väljer 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>
    

    Kodblocket <NotFound> är vad kunderna ser om de försöker gå till en sida som inte finns.

  2. I utforskaren expanderar du Sidor, högerklickar på mappen och väljer Ny fil.

  3. Ge den nya filen namnet Checkout.razor. Skriv följande kod i den här filen:

    @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;
    }
    

    Den här sidan bygger på den aktuella appen och använder apptillståndet som sparats i OrderState. Den första div är appens nya sidhuvudnavigering. Nu ska vi lägga till den på indexsidan.

  4. I utforskaren expanderar du Sidor och väljer sedan index.razor.

  5. Lägg till html ovanför <div class="main">top-bar klassen.

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

    När vi är på den här sidan skulle det vara trevligt att visa kunderna genom att markera länken. Teamet har redan skapat en active css-klass, så lägg till active det class attribut som redan innehåller nav-tab formatet.

    <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. I Visual Studio Code väljer du F5. Eller på menyn Kör väljer du Starta felsökning.

    Appen har nu en fin menyrad högst upp, som innehåller företagets logotyp. Lägg till några pizzor och välj knappen Order för att gå vidare till utcheckningssidan. Du ser pizzorna i listan och den aktiva indikatorn som saknas på menyn.

    Skärmbild som visar utcheckningssidan med några pizzor.

  7. Om du vill stoppa appen väljer du Skift + F5.

Tillåt kunder att göra en beställning

För närvarande tillåter inte utcheckningssidan kunder att göra sina beställningar. Logiken i appen måste lagra beställningen för att skicka till köket. När beställningen har skickats omdirigerar vi kunder tillbaka till startsidan.

  1. I utforskaren expanderar du Sidor och väljer Checkout.razor.

  2. Ändra knappelementet med ett anrop till PlaceOrder metoden. Lägg till attributen @onclick och disabled enligt följande:

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

    Vi vill inte att kunder ska lägga dubblettbeställningar, så vi inaktiverar knappen Order tills beställningen bearbetas.

  3. Lägg till den @code här koden under koden i Order Order => OrderState.Order; blocket.

    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("/");
    }
    

    Föregående kod inaktiverar knappen Lägg beställning, publicerar JSON och lägger till den till pizza.db, rensar ordern och använder NavigationManager för att omdirigera kunder till startsidan.

    Du måste lägga till kod för att hantera ordern. Lägg till en OrderController-klass för den här uppgiften. Om du tittar på PizzaStoreContext.cs ser du bara stöd för entitetsramverkets databas för PizzaSpecials. Vi fixar det först.

Lägga till stöd för entitetsramverk för beställningar och pizzor

  1. I utforskaren väljer du PizzaStoreContext.cs.

  2. PizzaStoreContext Ersätt klassen med den här koden:

    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();
        }
    }
    

    Den här koden lägger till stöd för entity framework för appens order- och pizzaklasser.

  3. I Visual Studio Code går du till menyn och väljer Arkiv>Ny fil.

  4. Ange OrderController.cs som filnamn. Se till att du sparar filen i samma katalog som OrderState.cs.

  5. Lägg till följande kod:

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

    Med föregående kod kan vår app hämta alla aktuella beställningar och göra en beställning. Med [Route("orders")] attributet Blazor kan den här klassen hantera inkommande HTTP-begäranden för /orders och /orders/{orderId}.

  6. Spara ändringarna med Ctrl+S.

  7. I utforskaren väljer du OrderState.cs.

  8. Längst ned i klassen under RemoveConfiguredPizza metoden ändrar du ResetOrder() för att återställa ordningen:

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

Testa funktionen för utcheckning

  1. I Visual Studio Code väljer du F5. Eller på menyn Kör väljer du Starta felsökning.

    Appen bör kompileras, men om du skapar en beställning och försöker checka ut visas ett körningsfel. Felet beror på att vår pizza.db SQLLite-databas skapades innan det fanns stöd för beställningar och pizzor. Vi måste ta bort filen så att en ny databas kan skapas korrekt.

  2. Om du vill stoppa appen väljer du Skift + F5.

  3. Ta bort filen pizza.db i utforskaren.

  4. Välj F5. Eller på menyn Kör väljer du Starta felsökning.

    Som ett test lägger du till pizzor, går till kassan och gör en beställning. Du omdirigeras till startsidan och du kan se att ordningen nu är tom.

  5. Om du vill stoppa appen väljer du Skift + F5.

Appen förbättras. Vi har pizzakonfiguration och en kassa. Vi vill att kunderna ska kunna se status för sin pizzabeställning när de har lagt den.

Lägg till en ordersida

  1. I utforskaren expanderar du Sidor, högerklickar på mappen och väljer Ny fil.

  2. Ge den nya filen namnet MyOrders.razor. Skriv följande kod i den här filen:

    @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");
        }
    }
    

    Navigeringen måste ändras på alla sidor som vi nu har för att inkludera en länk till den nya sidan Mina beställningar . Öppna Checkout.razor och Index.razor och ersätt navigeringen med den här koden:

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

    Genom att använda <a> element kan vi hantera vilken som är den aktiva sidan manuellt genom att lägga till active css-klassen. Nu ska vi uppdatera allt navigering för att använda en NavLink-komponent i stället.

  3. På alla tre sidorna med navigering (Index.razor, Checkout.razor och MyOrders.razor) använder du samma Blazor-kod för navigering:

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

    Css-klassen active läggs nu automatiskt till på sidor av NavLink-komponenten . Du behöver inte komma ihåg att göra det på varje sida som navigeringen är på.

  4. Det sista steget är att ändra NavigationManager omdirigeringen till myorders sidan när en beställning har gjorts. I utforskaren expanderar du Sidor och väljer sedan Checkout.razor.

  5. PlaceOrder Ändra metoden för att omdirigera till rätt sida genom att skicka /myorders till 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. I Visual Studio Code väljer du F5. Eller på menyn Kör väljer du Starta felsökning.

    Skärmbild som visar ordersidan.

    Du bör kunna beställa några pizzor och sedan se beställningarna för närvarande i databasen.

  7. Stoppa appen genom att välja Skift + F5.