從 Blazor 元件存取資料

已完成

如果要讓網站足夠吸引人,就得讓網站顯示可能隨時變更的動態內容。 從資料庫或 Web 服務這類動態來源取得資料,是 Web 開發的基礎技術。

假設您為披薩外送公司工作,負責其經過更新且能與客戶互動的網站。 且您有一系列的網頁配置,設計為 Blazor 元件。 而您現在想將要從資料庫取得的披薩、配料和訂單相關資訊填入這些頁面中。

在本單元內,您將了解如何存取資料,並在 HTML 標記中加以轉譯,以向使用者顯示。

建立已註冊的資料服務

如果您想建立會向使用者顯示動態資訊的動態網站,您就必須撰寫程式碼來從某處取得該等資料。 例如,假設您有個資料庫,其中儲存您公司所銷售的所有披薩。 因為披薩類型會一直變更,所以將其硬式編碼至網站 HTML 是個壞點子。 您應該改為使用 C# 程式碼和 Blazor 來查詢資料庫,接著將詳細資料格式化為 HTML,讓使用者能挑選他們最愛的披薩。

在 Blazor Server 應用程式中,您可以建立已註冊的服務來代表資料來源,並從中取得資料。

注意

您可以在 Blazor 應用程式中使用的資料來源包括關係資料庫、NoSQL 資料庫、Web 服務、各種 Azure 服務,以及其他許多系統。 您可以使用 Entity Framework、HTTP 用戶端和 ODBC 這類 .NET 技術來查詢這些來源。 這些技術超出本課程模組的範圍。 接下來,您將學習如何將透過這些來源和技術所取得的資料格式化並加以使用。

已註冊服務的建立從撰寫定義其屬性的類別開始。 以下是您可能撰寫來代表披薩的範例:

namespace BlazingPizza.Data;

public class Pizza
{
    public int PizzaId { get; set; }
    
    public string Name { get; set; }
    
    public string Description { get; set; }
    
    public decimal Price { get; set; }
    
    public bool Vegetarian { get; set; }
    
    public bool Vegan { get; set; }
}

類別會定義披薩的屬性和資料類型。 您必須確定這些屬性符合資料來源中的披薩結構描述。 在專案的 Data 資料夾中建立此類別,並使用稱為 Data 的成員命名空間,這樣相當合理。 想要的話,您也可以選擇其他資料夾和命名空間。

接下來,您將定義服務:

namespace BlazingPizza.Data;

public class PizzaService
{
    public Task<Pizza[]> GetPizzasAsync()
    {
    // Call your data access technology here
    }
}

請注意,服務會使用非同步呼叫來存取資料,並傳回 Pizza 物件的集合。 資料來源可能與 Blazor 程式碼所執行的伺服器相距甚遠。 在該情況下,請使用非同步呼叫。 然後,如果資料來源回應緩慢,其他程式碼可以在等候回應時繼續執行。

您也必須在 Program.cs 檔案的 Add Services to the container 區段中新增程式碼行,以註冊服務:

...
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
// Register the pizzas service
builder.Services.AddSingleton<PizzaService>();
...

使用服務來取得資料

現在您會使用您定義的服務來取得資料,方法是在 Blazor 元件中呼叫它。 假設您有下列元件程式碼,而且您想要在其中顯示披薩:

@page "/pizzas"

<h1>Choose your pizza</h1>

<p>We have all these delicious recipes:</p>

插入服務

您必須先使用相依性插入來新增服務,才能從元件呼叫服務。 在 @page 指示詞後面新增下列程式碼來插入服務:

@using BlazingPizza.Data
@inject PizzaService PizzaSvc

元件和服務通常位於不同的命名空間成員中,因此您必須包括 @using 指示詞。 此指示詞的運作方式與 C# 程式碼檔案頂端的 using 陳述式相同。 @inject 指示詞會將服務新增至目前的元件,並起始其執行個體。 請在指示詞中指定服務類別的名稱。 並在後面接著此元件中您要為服務的執行個體所使用的名稱。

覆寫 OnInitializedAsync 方法

OnInitializedAsync 方法中有呼叫服務以及取得資料的好位置。 此事件會在元件初始化完成且收到初始參數,但在轉譯並向使用者顯示頁面之前引發。 事件定義於 Blazor 元件的基底類別上。 您可以在程式碼區塊中予以覆寫,如此範例所示:

protected override async Task OnInitializedAsync()
{
    \\ Call the service here
}

呼叫服務來取得資料

當您呼叫服務時,請使用 await 關鍵字,因為呼叫屬於非同步呼叫:

private Pizza[] todaysPizzas;

protected override async Task OnInitializedAsync()
{
    todaysPizzas = await PizzaSvc.GetPizzasAsync();
}

向使用者顯示資料

從服務取得一些資料之後,您將會想要向使用者顯示那些資料。 在披薩範例中,我們預期服務會傳回披薩的清單,讓使用者可以選自己要的披薩。 Blazor 包含一組豐富的指示詞,可讓您用來將此資料插入使用者看到的頁面。

檢查資料

首先,請判斷頁面在載入披薩之前顯示的內容。 我們可以檢查 todaysPizzas 集合是否為 null 來達到目的。 若要在 Blazor 元件中執行條件式轉譯程式碼,請使用 @if 指示詞:

@if (todaysPizzas == null)
{
    <p>We're finding out what pizzas are available today...</p>
}
else
{
    <!-- This markup will be rendered once the pizzas are loaded -->
}

只有在 C# 運算式傳回 true 時,@if 指示詞才會在其第一個程式碼區塊中轉譯標記。 您也可以使用 else if 程式碼區塊來執行其他測試,並在其為 true 時轉譯標記。 最後,如果先前沒有任何條件傳回 true,則您可以指定 else 程式碼區塊來轉譯程式碼。 在 @if 程式碼區塊中檢查 null,即可確保 Blazor 不會在從服務取得資料之前嘗試顯示披薩詳細資料。

注意

Blazor 也會包括 @switch 指示詞,用於在可能傳回多個值的測試上轉譯標記。 @switch 指示詞的運作方式與 C# switch 陳述式類似。

轉譯物件的集合

如果 Blazor 在上述程式碼中執行 else 陳述式,您就會知道某些披薩是從服務取得的。 下一個工作是向使用者顯示這些披薩。 讓我們看看如何在簡單的 HTML 資料表中顯示資料。

當我們撰寫此頁面時,我們不知道有多少披薩可用。 我們可以使用 @foreach 指示詞對 todaysPizzas 集合中的所有物件執行迴圈,並為每個物件轉譯一個資料列:

<table>
 <thead>
  <tr>
   <th>Pizza Name</th>
   <th>Description</th>
   <th>Vegetarian?</th>
   <th>Vegan?</th>
   <th>Price</th>
  </tr>
 </thead>
 <tbody>
  @foreach (var pizza in todaysPizzas)
  {
   <tr>
    <td>@pizza.Name</td>
    <td>@pizza.Description</td>
    <td>@pizza.Vegetarian</td>
    <td>@pizza.Vegan</td>
    <td>@pizza.Price</td>
   </tr>
  }
 </tbody>
</table>

Screenshot showing how the list of pizzas appears on a Blazor component.

比起此範例中顯示的單純資料表來說,您當然可能希望更豐富的披薩顯示方法。 您可能會想要將價格和其他值格式化。 請與您的圖表設計師合作,開發出更吸引人的 UI。 例如,包括每款披薩的圖片。

注意

Blazor 包括其他迴圈指示詞,例如 @for@while@do while。 這些指示詞會傳回重複的標記區塊。 它們的運作方式類似於 C# 中對等的 forwhiledo...while 迴圈。

在下一個單元中,您將註冊自己的資料服務!

檢定您的知識

1.

哪一個 Blazor 事件處理常式是擷取資料的好位置?

2.

您應該使用哪一個 Blazor 指示詞來處理 Blazor 頁面上的資料存取服務?