연습 - Blazor 구성 요소에서 데이터 액세스
현재 앱에 하드 코드된 피자를 데이터베이스로 바꾸어야 합니다. Microsoft Entity Framework를 사용하면 데이터 원본에 대한 연결을 추가할 수 있습니다. 이 앱에서 SQLite 데이터베이스를 사용하여 피자를 저장합니다.
이 연습에서는 데이터베이스 기능을 지원하는 패키지를 추가하고, 클래스를 백 엔드 데이터베이스에 연결하고, 회사의 피자 데이터를 미리 로드하는 도우미 클래스를 추가합니다.
데이터베이스 액세스를 지원하는 패키지 추가
앱이 계속 실행되고 있으면 중지합니다.
Visual Studio Code 내에서 터미널>새 터미널을 선택합니다.
새 터미널 창에서 위치를 BlazingPizza 디렉터리로 설정합니다.
cd BlazingPizza
다음 명령을 실행하여 Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Sqlite 및 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
다음 명령은 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>
데이터베이스 컨텍스트 추가
Visual Studio Code에서 BlazingPizza 폴더에 새 폴더를 만듭니다. 이름을 Data로 지정합니다.
Data 폴더에 새 파일을 만듭니다. 이름을 PizzaStoreContext.cs로 지정합니다.
클래스에 대해 다음 코드를 입력합니다.
using Microsoft.EntityFrameworkCore; namespace BlazingPizza.Data; public class PizzaStoreContext : DbContext { public PizzaStoreContext(DbContextOptions options) : base(options) { } public DbSet<PizzaSpecial> Specials { get; set; } }
이 클래스는 데이터베이스 서비스를 등록하는 데 사용할 수 있는 데이터베이스 컨텍스트를 만듭니다. 컨텍스트를 사용하면 데이터베이스에 액세스하는 컨트롤러를 사용할 수도 있습니다.
변경 내용을 저장합니다.
컨트롤러 추가
BlazingPizza 폴더에 새 폴더를 만듭니다. 이름을 Controllers로 지정합니다.
Controllers 폴더에 새 파일을 만듭니다. 이름을 SpecialsController.cs로 지정합니다.
클래스에 대해 다음 코드를 입력합니다.
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(); } }
이 클래스는 피자 스페셜에 대한 데이터베이스를 쿼리하고
(http://localhost:5000/specials)
URL에서 JSON으로 반환할 수 있는 컨트롤러를 만듭니다.변경 내용을 저장합니다.
데이터베이스에 데이터 로드
앱은 기존 SQLite 데이터베이스가 있는지 확인하고 미리 만든 피자를 사용하여 데이터베이스를 하나 만듭니다.
Data 디렉터리에 새 파일을 만듭니다. 이름을 SeedData.cs로 지정합니다.
클래스에 대해 다음 코드를 입력합니다.
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
개체를 만든 다음 저장합니다.파일 탐색기에서 Program.cs를 선택합니다.
맨 위쪽에서 새
PizzaStoreContext
에 대한 참조를 추가합니다.using BlazingPizza.Data;
이 문을 사용하면 앱이 새 서비스를 사용할 수 있습니다.
다음 세그먼트를
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
정적 클래스를 호출하여 데이터베이스를 만듭니다.지금은
PizzaStoreContext
를 초기화하지 않았기 때문에 앱이 작동하지 않습니다. Program.cs 파일의Add Services to the container
상위 섹션에서 현재 서비스(builder.Services.
를 시작하는 줄) 아래에 다음 코드를 추가합니다.builder.Services.AddHttpClient(); builder.Services.AddSqlite<PizzaStoreContext>("Data Source=pizza.db");
이 코드는 두 서비스를 등록합니다. 첫 번째
AddHttpClient
문을 사용하면 앱이 HTTP 명령에 액세스할 수 있습니다. 앱은 HttpClient를 사용하여 피자 스페셜에 대한 JSON을 가져옵니다. 두 번째 문은 새PizzaStoreContext
를 등록하고 SQLite 데이터베이스의 파일 이름을 제공합니다.
데이터베이스를 사용하여 피자 표시
이제 Index.razor 페이지에서 하드 코드된 피자를 바꿀 수 있습니다.
파일 탐색기에서 Index.razor를 선택합니다.
기존
OnInitialized()
메서드를 다음으로 바꿉니다.protected override async Task OnInitializedAsync() { specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials"); }
참고
이 코드는
OnInitialized()
를OnInitializedAsync()
로 대체합니다. 이제 스페셜이 앱에서 비동기식으로 JSON으로 반환됩니다.수정해야 하는 몇 가지 오류가 있습니다.
@page
지시문 아래에 다음@inject
문을 추가합니다.@inject HttpClient HttpClient @inject NavigationManager NavigationManager
모든 변경 내용을 저장한 다음, F5를 선택하거나 실행을 선택합니다. 그런 다음, 디버깅 시작을 선택합니다.
앱을 실행할 때 런타임 오류가 발생합니다. JsonReader에서 예외가 발생했습니다.
앱은
(http://localhost:5000/specials)
에서 JSON을 만들어야 합니다. 해당 URL로 이동합니다.앱은 이 요청을 라우팅하는 방법을 모릅니다. 라우팅에 대해서는 Blazor 라우팅 모듈에서 알아봅니다. 이제 오류를 해결해 보겠습니다.
Shift + F5를 선택하거나 디버깅 중지를 선택합니다.
파일 탐색기에서 Program.cs를 선택합니다.
파일 중간에
app.
를 시작하는 줄 뒤에 다음 엔드포인트를 추가합니다.app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
이제 코드는 다음과 같습니다.
... app.MapRazorPages(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host"); app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}"); ...
F5를 선택하거나 실행을 선택합니다. 그런 다음, 디버깅 시작을 선택합니다.
이제 앱이 작동하지만 JSON이 올바르게 생성되고 있는지 확인해 보겠습니다.
(http://localhost:5000/specials)
로 이동하여 다음을 확인하세요.JSON에는 스페셜 피자 컨트롤러에 지정된 대로 가격이 내림차순으로 나열된 피자가 있습니다.