第十三章:Blazor WebAssembly UI 開發
13.1 引言:C# 全端開發的夢想
Blazor WebAssembly (WASM) 允許開發者使用 C# 而非 JavaScript 來編寫前端應用程式。這對於 .NET 開發者來說是一個巨大的優勢,因為我們可以:
- 共用 DTO 與邏輯:前後端共用
Application.Contracts與Domain.Shared。 - 強型別開發:享受編譯器檢查與 IntelliSense。
- 統一技術堆疊:不需要學習 React/Angular/Vue。
ABP Framework 為 Blazor 提供了深度的整合,包括預建的 UI 元件、自動授權與多語言支援。
13.2 專案結構與啟動
當您使用 -u blazor 建立專案時,會多出一個 Blazor 專案。
1. Blazor 專案結構
Program.cs:設定 WASM 宿主、註冊服務 (DI)。App.razor:路由入口。Menus/:定義選單結構。Pages/:Razor 頁面元件。
2. Blazorise 元件庫
ABP 社群版預設使用 Blazorise 作為 UI 框架 (通常搭配 Bootstrap 5 提供者)。
- 優勢:跨 CSS 框架的抽象層。您可以切換底層 CSS (Bootstrap, Bulma, AntDesign) 而不需修改 Razor 程式碼。
- V10.0 更新:升級至 Blazorise 1.8.6,帶來了更多的元件與效能改進。
13.3 開發 Blazor 頁面
1. 頁面定義 (@page)
csharp
@page "/books"
@using Volo.Abp.Application.Dtos
@inherits AbpCrudPageBase<IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto>- 繼承基類:
AbpCrudPageBase是一個強大的基類,它內建了 CRUD 所需的大部分邏輯 (載入列表、分頁、排序、建立/編輯 Modal 控制)。
2. 注入服務 (@inject)
csharp
@inject IBookAppService BookAppService
@inject IStringLocalizer<BookStoreResource> L3. 使用 Blazorise 元件
html
<Card>
<CardHeader>
<Row Class="justify-content-between">
<Column ColumnSize="ColumnSize.IsAuto">
<h2>@L["Books"]</h2>
</Column>
<Column ColumnSize="ColumnSize.IsAuto">
<button Color="Color.Primary" Clicked="OpenCreateModalAsync">
<Icon Name="IconName.Add" /> @L["NewBook"]
</button>
</Column>
</Row>
</CardHeader>
<CardBody>
<DataGrid
TItem="BookDto"
Data="Entities"
ReadData="OnDataGridReadAsync"
TotalItems="TotalCount"
ShowPager="true"
PageSize="PageSize"
>
<DataGridColumn TItem="BookDto" Field="@nameof(BookDto.Name)"
Caption="@L["Name"]" /> <DataGridColumn TItem="BookDto"
Field="@nameof(BookDto.Price)" Caption="@L["Price"]" />
<DataGridEntityActionsColumn TItem="BookDto" @ref="EntityActionsColumn">
<DisplayTemplate>
<EntityActions
TItem="BookDto"
EntityActionsColumn="@EntityActionsColumn"
>
<EntityAction TItem="BookDto" Text="@L["Edit"]" Clicked="() =>
OpenEditModalAsync(context)" /> <EntityAction TItem="BookDto"
Text="@L["Delete"]" Clicked="() => DeleteEntityAsync(context)"
ConfirmationMessage="Are you sure?" />
</EntityActions>
</DisplayTemplate>
</DataGridEntityActionsColumn>
</DataGrid>
</CardBody>
</Card>- DataGrid:Blazorise 的核心元件,支援分頁、排序、篩選。
- EntityActions:ABP 封裝的下拉選單,用於操作單一列。
13.4 狀態管理與資料流
1. C# API 代理 (C# API Proxies)
與 MVC 的 JS Proxy 類似,ABP 也為 Blazor 生成了 C# Proxy。
- HttpApi.Client 專案:負責生成這些 Proxy。
- 使用方式:直接注入介面
IBookAppService。在執行時,它會透過HttpClient發送 REST 請求到後端 API。
2. 授權 (Authorization)
ABP Blazor 範本整合了 Microsoft.AspNetCore.Components.WebAssembly.Authentication。
- AccessToken:自動附加到每個 HTTP 請求的 Header 中。
- AuthorizeView:html
<AuthorizeView Policy="BookStore.Books.Create"> <Authorized> <button ...>Create</button> </Authorized> </AuthorizeView>
13.5 效能優化技巧
Blazor WASM 的主要缺點是 首次載入時間 (Initial Load Time)。
1. 延遲載入 (Lazy Loading)
將不常用的模組 (如 Admin 頁面) 設定為延遲載入。ABP 支援模組級別的延遲載入。
2. 減少傳輸量
- 使用 Brotli 壓縮 (預設開啟)。
- 移除不必要的 NuGet 套件引用。
3. 虛擬化 (Virtualization)
對於長列表,使用 <Virtualize> 元件,只渲染可見區域的項目。
html
<Virtualize Items="@AllBooks" Context="book">
<tr>
<td>@book.Name</td>
</tr>
</Virtualize>13.6 實戰練習
練習 1:建立 CRUD 頁面
- 建立
Books.razor。 - 繼承
AbpCrudPageBase。 - 使用
DataGrid顯示書籍列表。 - 實作
CreateModal與EditModal(使用Modal元件)。
練習 2:實作權限控制
- 在
Books.razor上方加入@attribute [Authorize("BookStore.Books")]。 - 在 "新增按鈕" 外圍包裹
<AuthorizeView Policy="BookStore.Books.Create">。 - 使用不同權限的使用者登入測試。
練習 3:自訂元件
- 建立一個
BookCard.razor元件,用於以卡片形式顯示書籍資訊。 - 定義
[Parameter] public BookDto Book { get; set; }。 - 在
Books.razor中使用此元件。
13.7 總結
Blazor WebAssembly 讓 .NET 開發者能以熟悉的語言構建現代化的 SPA。
- Blazorise 提供了豐富的 UI 元件。
- AbpCrudPageBase 大幅簡化了 CRUD 開發。
- C# Proxy 讓前後端通訊變得透明。
至此,我們已經涵蓋了 ABP 的兩種主要 UI 模式 (MVC 與 Blazor)。在接下來的 第四部:進階架構 中,我們將探討微服務、模組化開發與多租戶等進階主題。
參考資源: