練習 - 從 Blazor 元件存取資料

已完成

應用程式中目前的硬式編碼披薩必須以資料庫取代。 您可使用 Microsoft Entity Framework 將連線新增至資料來源。 在此應用程式中,我們將使用 SQLite 資料庫來儲存披薩。

在此練習中,您將新增套件以支援資料庫功能、將類別連線到後端資料庫,以及新增協助程式類別來預先載入公司的披薩資料。

新增套件以支援資料庫存取

  1. 停止仍在執行的應用程式。

  2. 在 Visual Studio Code 中,選取 [終端]>[新增終端]

  3. 在新的終端中,將位置設定為 BlazingPizza 目錄。

    cd BlazingPizza
    
  4. 執行下列命令,以新增 Microsoft.EntityFrameworkCoreMicrosoft.EntityFrameworkCore.SqliteSystem.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>
    

新增資料庫內容

  1. 在 Visual Studio Code 中,於 BlazingPizza 資料夾內建立新的資料夾。 將其命名為 Data

  2. Data 資料夾中建立新的檔案。 將其命名為 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. 儲存您的變更。

新增控制器

  1. BlazingPizza 資料夾中建立新的資料夾。 將其命名為 Controllers

  2. Controllers 資料夾中建立新的檔案。 將其命名為 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();
        }
    }
    

    此類別會建立控制器,讓我們查詢資料庫是否有特製披薩,並在 (http://localhost:5000/specials) URL 以 JSON 形式傳回。

  4. 儲存您的變更。

將資料載入資料庫

應用程式會查看是否有現有的 SQLite 資料庫,並使用一些預先製作的披薩來建立一個資料庫。

  1. Data 目錄中建立新的檔案。 將其命名為 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 檔案中較高位置的 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 頁面中取代硬式編碼的披薩。

  1. 在檔案總管中,選取 Index.razor

  2. 將現有的 OnInitialized() 方法取代為:

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

    注意

    此程式碼已將 OnInitialized() 取代為 OnInitializedAsync()。 特製披薩現在會以非同步方式從應用程式傳回為 JSON。

  3. 有一些您需要修正的錯誤。 在 @page 指示詞下新增這些 @inject 陳述式:

    @inject HttpClient HttpClient
    @inject NavigationManager NavigationManager
    
  4. 儲存所有變更,然後選取 F5 或選取 [執行]。 然後選取 [開始偵錯]

    執行應用程式時發生執行階段錯誤。 JsonReader 引發了例外狀況。

  5. 請記住,應用程式應該在 (http://localhost:5000/specials) 建立 JSON。 前往該 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) 以查看:

    Screenshot showing the browser that shows JSON for pizzas.

    JSON 會依特殊披薩控制器中指定的價格遞減列出披薩。

    Screenshot showing even more blazing pizzas.