Esercizio: Accedere ai dati da un componente Blazor

Completato

È necessario sostituire le pizze correnti specificate nell'app a livello di codice con un database. È possibile usare Microsoft Entity Framework per aggiungere connessioni alle origini dati. In questa app verrà usato un database SQLite per archiviare le pizze.

In questo esercizio si aggiungeranno pacchetti per supportare la funzionalità del database, connettere classi a un database back-end e aggiungere una classe helper per precaricare i dati relative alle pizze per la società.

Aggiungere pacchetti per supportare l'accesso al database

  1. Arrestare l'app se è ancora in esecuzione.

  2. In Visual Studio Code selezionare Terminale>Nuovo terminale.

  3. Nel nuovo terminale impostare la posizione sulla directory BlazingPizza.

    cd BlazingPizza
    
  4. Eseguire questi comandi per aggiungere i pacchetti Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Sqlite e System.Net.Http.Json:

    dotnet add package Microsoft.EntityFrameworkCore --version 6.0.8
    dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 6.0.8
    dotnet add package System.Net.Http.Json --version 6.0.0
    

    Questi comandi consentono di aggiungere riferimenti ai pacchetti al file BlazingPizza.csproj:

      <ItemGroup>
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.8" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
        <PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
      </ItemGroup>
    

Aggiungere un contesto di database

  1. In Visual Studio Code creare una nuova cartella nella cartella BlazingPizza. Assegnare alla cartella il nome Data.

  2. Creare un nuovo file nella cartella Data. Assegnare al file il nome PizzaStoreContext.cs.

  3. Immettere il codice seguente per la classe:

    using Microsoft.EntityFrameworkCore;
    
    namespace BlazingPizza.Data;
    
    public class PizzaStoreContext : DbContext
    {
        public PizzaStoreContext(DbContextOptions options) : base(options)
        {
        }
    
        public DbSet<PizzaSpecial> Specials { get; set; }
    }    
    

    Questa classe consente di creare un contesto di database che è possibile usare per registrare un servizio di database. Il contesto consente anche di definire un controller che accede al database.

  4. Salvare le modifiche.

Aggiungere un controller

  1. Creare una nuova cartella nella cartella BlazingPizza. Assegnare alla cartella il nome Controllers.

  2. Creare un nuovo file nella cartella Controllers. Assegnare al file il nome SpecialsController.cs.

  3. Immettere il codice seguente per la classe:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using BlazingPizza.Data;
    
    namespace BlazingPizza.Controllers;
    
    [Route("specials")]
    [ApiController]
    public class SpecialsController : Controller
    {
        private readonly PizzaStoreContext _db;
    
        public SpecialsController(PizzaStoreContext db)
        {
            _db = db;
        }
    
        [HttpGet]
        public async Task<ActionResult<List<PizzaSpecial>>> GetSpecials()
        {
            return (await _db.Specials.ToListAsync()).OrderByDescending(s => s.BasePrice).ToList();
        }
    }
    

    Questa classe crea un controller che consente di eseguire query sul database per le pizze speciali e di restituirle in formato JSON nell'URL (http://localhost:5000/specials).

  4. Salvare le modifiche.

Caricare i dati nel database

L'app verifica se è presente un database SQLite esistente e ne crea uno con alcune pizze predefinite.

  1. Creare un nuovo file nella directory Data. Assegnare al file il nome SeedData.cs.

  2. Immettere il codice seguente per la classe:

    namespace BlazingPizza.Data;
    
    public static class SeedData
    {
        public static void Initialize(PizzaStoreContext db)
        {
            var specials = new PizzaSpecial[]
            {
                new PizzaSpecial()
                {
                    Name = "Basic Cheese Pizza",
                    Description = "It's cheesy and delicious. Why wouldn't you want one?",
                    BasePrice = 9.99m,
                    ImageUrl = "img/pizzas/cheese.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 2,
                    Name = "The Baconatorizor",
                    Description = "It has EVERY kind of bacon",
                    BasePrice = 11.99m,
                    ImageUrl = "img/pizzas/bacon.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 3,
                    Name = "Classic pepperoni",
                    Description = "It's the pizza you grew up with, but Blazing hot!",
                    BasePrice = 10.50m,
                    ImageUrl = "img/pizzas/pepperoni.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 4,
                    Name = "Buffalo chicken",
                    Description = "Spicy chicken, hot sauce and bleu cheese, guaranteed to warm you up",
                    BasePrice = 12.75m,
                    ImageUrl = "img/pizzas/meaty.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 5,
                    Name = "Mushroom Lovers",
                    Description = "It has mushrooms. Isn't that obvious?",
                    BasePrice = 11.00m,
                    ImageUrl = "img/pizzas/mushroom.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 7,
                    Name = "Veggie Delight",
                    Description = "It's like salad, but on a pizza",
                    BasePrice = 11.50m,
                    ImageUrl = "img/pizzas/salad.jpg",
                },
                new PizzaSpecial()
                {
                    Id = 8,
                    Name = "Margherita",
                    Description = "Traditional Italian pizza with tomatoes and basil",
                    BasePrice = 9.99m,
                    ImageUrl = "img/pizzas/margherita.jpg",
                },
            };
            db.Specials.AddRange(specials);
            db.SaveChanges();
        }
    }
    

    La classe usa un contesto di database passato, crea alcuni oggetti PizzaSpecial in una matrice e li salva.

  3. In Esplora file selezionare Program.cs.

  4. Nella parte iniziale aggiungere un riferimento a un nuovo oggetto PizzaStoreContext:

    using BlazingPizza.Data;
    

    Questa istruzione consente all'app di usare il nuovo servizio.

  5. Inserire questo segmento sopra il metodo app.Run();:

    ...
    // Initialize the database
    var scopeFactory = app.Services.GetRequiredService<IServiceScopeFactory>();
    using (var scope = scopeFactory.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<PizzaStoreContext>();
        if (db.Database.EnsureCreated())
        {
            SeedData.Initialize(db);
        }
    }
    
    app.Run();
    

    Questa modifica consente di creare un ambito di database con l'oggetto PizzaStoreContext. Se non è già stato creato un database, chiama la classe statica SeedData per crearne uno.

  6. Al momento, l'app non funziona perché non è stato inizializzato PizzaStoreContext. Nella sezione Add Services to the container all'inizio del file Program.cs aggiungere questo codice sotto i servizi correnti, ovvero le righe che iniziano con builder.Services.:

      builder.Services.AddHttpClient();
      builder.Services.AddSqlite<PizzaStoreContext>("Data Source=pizza.db");
    
    

    Questo codice consente di registrare due servizi. La prima istruzione AddHttpClient consente all'app di accedere ai comandi HTTP. L'app usa un oggetto HttpClient per ottenere il codice JSON per le pizze speciali. La seconda istruzione registra il nuovo oggetto PizzaStoreContext e fornisce il nome file per il database SQLite.

Usare il database per visualizzare le pizze

È ora possibile sostituire la pizza specificata a livello di codice nella pagina index.razor.

  1. In Esplora file selezionare Index.razor.

  2. Sostituire il metodo OnInitialized() esistente con:

    protected override async Task OnInitializedAsync()
    {
        specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials");
    }
    

    Nota

    In questo codice OnInitialized() è stato sostituito con OnInitializedAsync(). Le pizze speciali verranno ora restituite in formato JSON dall'app in modo asincrono.

  3. Sono presenti errori che è necessario correggere. Aggiungere queste istruzioni @inject nella direttiva @page:

    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
  4. Salvare tutte le modifiche, quindi selezionare F5 o Esegui. Selezionare quindi Avvia debug.

    Si verifica un errore di runtime quando si esegue l'app. JsonReader ha generato un'eccezione.

  5. Tenere presente che l'app deve creare codice in formato JSON all'indirizzo (http://localhost:5000/specials). Passare a tale URL.

    L'app non sa come instradare questa richiesta. Il routing verrà illustrato nel modulo sul routing di Blazor. Al momento, si correggerà l'errore.

  6. Premere MAIUSC + F5 oppure selezionare Arresta debug.

  7. In Esplora file selezionare Program.cs.

  8. Aggiungere questo endpoint al centro del file, dopo le righe che iniziano con app.:

    app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    

    Il codice dovrebbe ora essere:

    ...
    app.MapRazorPages();
    app.MapBlazorHub();
    app.MapFallbackToPage("/_Host");
    app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    ...
    
  9. Premere F5 o selezionare Esegui. Selezionare quindi Avvia debug.

    L'app dovrebbe funzionare, ma è necessario verificare che il codice in formato JSON venga creato correttamente.

  10. Passare all'indirizzo (http://localhost:5000/specials) per verificarlo:

    Screenshot showing the browser that shows JSON for pizzas.

    Nel codice JSON le pizze sono elencate in ordine decrescente di prezzo, come specificato nel controller delle pizze speciali.

    Screenshot showing even more blazing pizzas.