练习 - 从 Blazor 组件访问数据
需要将应用中当前硬编码的披萨替换为数据库。 你可以使用 Microsoft 实体框架向数据源添加连接。 在本应用中,我们将使用 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 按照特价披萨控制器中指定的价格以降序列出了披萨。