Exercício: acessar dados de um componente Blazor

Concluído

As pizzas atuais codificadas no aplicativo precisam ser substituídas por um banco de dados. Você pode usar o Microsoft Entity Framework para adicionar conexões a fontes de dados. Neste aplicativo, usaremos um banco de dados SQLite para armazenar as pizzas.

Nesse exercício, você adicionará pacotes para dar suporte à funcionalidade do banco de dados, conectará nossas classes a um banco de dados de back-end e adicionará uma classe auxiliar para pré-carregar dados das pizzas da empresa.

Adicionar pacotes para dar suporte ao acesso ao banco de dados

  1. Interrompa o aplicativo se ele ainda estiver em execução.

  2. No Visual Studio Code, selecione Terminal>Novo Terminal.

  3. No novo terminal, defina sua localização para o diretório BlazingPizza.

    cd BlazingPizza
    
  4. Execute estes comandos para adicionar os pacotes 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
    

    Estes comandos adicionam referências de pacote ao arquivo 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>
    

Adicionar um contexto de banco de dados

  1. No Visual Studio Code, crie uma nova pasta em BlazingPizza. Nomeie-a Dados.

  2. Crie um arquivo dentro da pasta de Dados. Nomeie-o como PizzaStoreContext.cs.

  3. Insira este código para a classe:

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

    Essa classe cria um contexto de banco de dados que podemos usar para registrar um serviço de banco de dados. O contexto também nos permite ter um controlador que acessa o banco de dados.

  4. Salve suas alterações.

Adicionar um controlador

  1. Crie uma nova pasta BlazingPizza. Nomeie-a como Controladores.

  2. Crie um novo arquivo na pasta Controladores. Nomeie-o como SpecialsController.cs.

  3. Insira este código para a 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();
        }
    }
    

    Essa classe cria um controlador que permite consultar o banco de dados em busca de pizzas especiais e retorná-las como JSON na URL (http://localhost:5000/specials).

  4. Salve suas alterações.

Carregar dados no banco de dados

O aplicativo verifica se há um banco de dados SQLite existente e cria um com algumas pizzas pré-preparadas.

  1. Crie um novo arquivo no diretório de Dados. Nomeie-o como SeedData.cs.

  2. Insira este código para a 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();
        }
    }
    

    A classe usa um contexto de banco de dados passado, cria alguns objetos PizzaSpecial em uma matriz e os salva.

  3. No explorador de arquivos, selecione Program.cs.

  4. Na parte superior, adicione uma referência a um novo PizzaStoreContext:

    using BlazingPizza.Data;
    

    Essa instrução permite que o aplicativo use o novo serviço.

  5. Insira este segmento acima do método 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();
    

    Essa alteração cria um escopo do banco de dados com o PizzaStoreContext. Se não houver um banco de dados já criado, ele chamará a classe estática SeedData para criar um.

  6. No momento, o aplicativo não funciona porque não inicializamos o PizzaStoreContext. Na seção superior Add Services to the container do arquivo Program.cs, adicione este código nos serviços atuais (as linhas que iniciam builder.Services.):

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

    Esse código registra dois serviços. A primeira instrução AddHttpClient permite que o aplicativo acesse comandos HTTP. O aplicativo usa um HttpClient para obter o JSON para pizzas especiais. A segunda instrução registra o novo PizzaStoreContext e fornece o nome do arquivo para o banco de dados SQLite.

Usar o banco de dados para exibir pizzas

Agora, podemos substituir a pizza codificada na página index.razor.

  1. No explorador de arquivos, selecione Index.razor.

  2. Substitua o método OnInitialized() existente por:

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

    Observação

    Esse código substituiu OnInitialized() por OnInitializedAsync(). Agora, as especiais retornarão como JSON do aplicativo de forma assíncrona.

  3. Há alguns erros que você precisa corrigir. Adicione essas instruções @inject na diretiva @page:

    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
  4. Salve todas as alterações e selecione F5 ou Executar. Selecione Iniciar Depuração.

    Ocorre um erro de runtime ao executar o aplicativo. O JsonReader gerou uma exceção.

  5. Lembre-se de que o aplicativo deve criar o JSON em (http://localhost:5000/specials). Vá para essa URL.

    O aplicativo não sabe como rotear essa solicitação. Você aprenderá sobre roteamento no módulo sobre roteamento do Blazor. Vamos corrigir o erro.

  6. Selecione Shift + F5 ou selecione Parar Depuração.

  7. No explorador de arquivos, selecione Program.cs.

  8. No meio do arquivo, após as linhas iniciadas app., adicione este ponto de extremidade:

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

    Agora, o código deve ser:

    ...
    app.MapRazorPages();
    app.MapBlazorHub();
    app.MapFallbackToPage("/_Host");
    app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    ...
    
  9. Selecione F5 ou Executar. Selecione Iniciar Depuração.

    O aplicativo deve funcionar, mas vamos verificar se o JSON está sendo criado corretamente.

  10. Vá para (http://localhost:5000/specials) para ver:

    Screenshot showing the browser that shows JSON for pizzas.

    O JSON lista as pizzas em ordem decrescente de preço, conforme especificado no controlador de pizza especial.

    Screenshot showing even more blazing pizzas.