Упражнение. Доступ к данным из компонента Blazor

Завершено

Текущие жестко закодированные пиццы в приложении должны быть заменены базой данных. Microsoft Entity Framework можно использовать для добавления подключений к источникам данных. В этом приложении мы используем базу данных SQLite для хранения пиццы.

В этом упражнении вы добавите пакеты для поддержки функций базы данных, подключите классы к серверной базе данных и добавьте вспомогательный класс для предварительной загрузки данных для пиццы компании.

Добавление пакетов, поддерживающих доступ к базе данных

  1. Остановите приложение, если оно по-прежнему запущено.

  2. В Visual Studio Code выберите терминал>"Новый терминал".

  3. В новом терминале задайте расположение в каталоге BlazingPizza.

    cd BlazingPizza
    
  4. Выполните следующие команды, чтобы добавить пакеты Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Sqlite и System.Net.Http.Json:

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

    Эти команды добавляют ссылки на пакеты в файл BlazingPizza.csproj:

      <ItemGroup>
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0-*" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0-*" />
        <PackageReference Include="System.Net.Http.Json" Version="9.0.0-*" />
      </ItemGroup>
    

Добавление контекста базы данных

  1. В Visual Studio Code создайте новую папку в папке BlazingPizza . Назовите его data.

  2. В папке "Данные" создайте файл с именем PizzaStoreContext.cs.

  3. В новом файле введите этот код для класса:

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

    Этот класс создает контекст базы данных, который можно использовать для регистрации службы базы данных. Контекст также позволяет нам иметь контроллер, который обращается к базе данных.

  4. Сохраните изменения, нажав клавиши CTRL+S.

Добавление контроллера

  1. Создайте новую папку в папке BlazingPizza . Назовите это контроллеры.

  2. Создайте новый файл в папке контроллеров . Назовите его SpecialsController.cs.

  3. Введите этот код для класса:

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

    Этот класс создает контроллер, позволяющий запрашивать базу данных для специальных элементов пиццы и возвращать их в виде JSON по URL-адресу (http://localhost:5000/specials).

  4. Сохраните изменения.

Загрузка данных в базу данных

Приложение проверяет наличие существующей базы данных SQLite и, если её нет, создаёт новую с заранее подготовленными пиццами.

  1. Создайте новый файл в каталоге данных. Назовите его SeedData.cs.

  2. Введите этот код для класса:

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

    Класс использует переданный контекст базы данных, создает некоторые объекты PizzaSpecial в массиве, а затем сохраняет их.

  3. В проводнике выберите Program.cs.

  4. Вверху добавьте ссылку на новую PizzaStoreContext:

    using BlazingPizza.Data;
    

    Эта инструкция позволяет приложению использовать новую службу.

  5. Вставьте этот сегмент над методом 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();
    

    Это изменение создаёт область в базе данных с PizzaStoreContext. Если база данных еще не создана, она вызывает SeedData статический класс для создания.

  6. На данный момент приложение не работает, так как PizzaStoreContext еще не инициализирован. В файле Program.cs добавьте этот код в текущие службы (строки, начинающиеся builder.Services.):

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

    Этот код регистрирует две службы. Первая инструкция AddHttpClient позволяет приложению получать доступ к командам HTTP. Приложение использует HttpClient для получения JSON для специальных предложений по пицце. Вторая инструкция регистрирует новый PizzaStoreContext и предоставляет имя файла для базы данных SQLite.

Использование базы данных для отображения пицц

Теперь можно заменить жестко закодированную пиццу на странице Index.razor.

  1. В проводнике разверните страницы и выберите Index.razor.

  2. Замените существующий метод OnInitialized() следующим:

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

    Note

    Этот код заменяет OnInitialized() на OnInitializedAsync(). Специальные компоненты теперь будут возвращены в формате JSON из приложения асинхронно.

  3. Существуют некоторые ошибки, которые необходимо исправить. Добавьте эти инструкции @inject в директиву @page:

    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
  4. Сохраните все изменения, а затем выберите F5 или Запустить. Затем выберите начать отладку.

    При запуске приложения возникает ошибка среды выполнения. JsonReader вызвал исключение.

  5. Помните, что приложение должно создавать JSON в (http://localhost:5000/specials). Перейдите по url-адресу.

    Приложение не знает, как маршрутизировать этот запрос. Вы узнаете о маршрутизации в модуле Blazor, посвященном этому вопросу. Давайте исправим ошибку сейчас.

  6. Выберите SHIFT + F5 или нажмите кнопку "Остановить отладку".

  7. В проводнике выберите Program.cs.

  8. В середине файла после строк, начинающихся app., добавьте следующую конечную точку:

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

    Теперь код должен быть следующим:

    ...
    app.MapRazorPages();
    app.MapBlazorHub();
    app.MapFallbackToPage("/_Host");
    app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    ...
    
  9. Выберите F5 или выберите Запустить. Затем выберите начать отладку.

    Теперь приложение должно работать, но давайте проверим правильность создания JSON.

  10. Перейдите к (http://localhost:5000/specials), чтобы увидеть:

    снимок экрана с браузером, в котором отображается JSON для пиццы.

    JSON содержит список пицц в порядке убывания цены, как указано в специальном контроллере пиццы.

    снимок экрана, показывающий еще больше пылающих пицц.