从 Blazor 组件访问数据
- 7 分钟
吸引人的网站需要显示可能随时更改的动态内容。 从动态源(如数据库或 Web 服务)获取数据是 Web 开发中的基本技术。
假设你正在其更新的面向客户的网站上为披萨送货公司工作。 你有一系列布局和设计为 Blazor 组件的网页。 现在,你想要填充这些页面,其中包含要从数据库获取的披萨、配料和订单的相关信息。
在本单元中,你将了解如何访问数据并将其呈现在 HTML 标记中,以便向用户显示。
创建已注册的数据服务
如果要创建显示向用户更改信息的动态网站,则必须编写代码,以便从某个位置获取该数据。 例如,假设你有一个数据库,用于存储公司销售的所有披萨。 因为披萨总是在变化,所以将它们硬编码到网站 HTML 是个坏主意。 请使用 C# 代码和 Blazor 来查询数据库,然后将详细信息格式化为 HTML,以便用户可以选择他们的收藏项。
在 Blazor Server 应用中,可以创建一个已注册的服务来表示数据源并从中获取数据。
注释
Blazor 应用中可以使用的数据源包括关系数据库、NoSQL 数据库、Web 服务、各种 Azure 服务和其他许多系统。 可以使用实体框架、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
指令。 此指令的工作方式与 using
C# 代码文件顶部的语句相同。 该 @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>
当然,与此示例中显示的纯表相比,你可能希望显示更丰富的披萨内容。 你可能想要设置价格和其他值的格式。 与图形设计器协作开发更具吸引力的 UI。 例如,包括每个披萨的照片。
注释
Blazor 包括其他循环指令,例如 @for
, @while
和 @do while
。 这些指令返回重复的标记块。 它们的工作方式与等效的 C# for
while
和do...while
循环类似。
在下一单元中,你将注册自己的数据服务!