第十二章:MVC/Razor Pages 前端開發
12.1 引言:傳統但強大
雖然 SPA (Single Page Application) 是當前的趨勢,但 Server-Side Rendering (SSR) 在 SEO、首屏載入速度與開發簡單性上仍有不可取代的優勢。
ABP Framework 對 ASP.NET Core MVC / Razor Pages 做了大量的擴充,讓 SSR 開發體驗接近 SPA,同時保留了 SSR 的優點。
注意:若您選擇 Angular 作為前端,ABP V10 已全面支援 Angular 20、Esbuild 建置系統以及 SSR (Server-Side Rendering),提供了更佳的效能與 SEO 支援。本章將專注於 MVC / Razor Pages。
12.2 ABP Tag Helpers
ABP 提供了一套強大的 Tag Helpers,讓您能用宣告式的方式撰寫 Bootstrap UI,而無需記憶繁瑣的 CSS 類別。
1. 基礎元件
<!-- 按鈕 -->
<abp-button button-type="Primary" text="Save" icon="fa fa-save" />
<!-- 卡片 -->
<abp-card>
<abp-card-header>標題</abp-card-header>
<abp-card-body>內容...</abp-card-body>
</abp-card>
<!-- 表單輸入 (自動綁定 Label, Validation, Localization) -->
<abp-input asp-for="Book.Name" />2. 動態表單 (Dynamic Forms)
如果您不想手寫每個欄位,可以使用 abp-dynamic-form。
<abp-dynamic-form abp-model="Book" submit-button="true" />- 它會根據 DTO 的 Data Annotations 自動生成對應的 Input (Text, Number, Date, Checkbox)。
- 自動處理驗證訊息顯示。
3. 表格 (Table) 與分頁
ABP 整合了 Datatables.net (在某些範本中) 或提供純 Razor 的表格 Tag Helper。
<abp-table striped-rows="true">
<thead>
<tr>
<th>@L["Name"]</th>
<th>@L["Price"]</th>
</tr>
</thead>
<tbody>
@foreach (var book in Model.Books) {
<tr>
<td>@book.Name</td>
<td>@book.Price</td>
</tr>
}
</tbody>
</abp-table>
<!-- 分頁元件 -->
<abp-paginator model="Model.PagerModel" show-info="true" />12.3 JavaScript API 代理 (Dynamic JavaScript Proxies)
這是 ABP 前端開發的殺手級功能。您不需要手寫 fetch 或 axios 呼叫,ABP 會自動為您的 Application Service 生成 JavaScript 函式。
1. 引用腳本
在 _Layout.cshtml 中,ABP 已經自動注入了:
<script src="/Abp/ServiceProxyScript"></script>2. 呼叫 API
假設您有一個 BookAppService,包含 GetListAsync 方法。
// 命名空間對應 C# Namespace
var _bookService = volo.bookStore.books.book;
// 直接呼叫,回傳 Promise
_bookService
.getList({ maxResultCount: 10, skipCount: 0 })
.then(function (result) {
console.log(result.items); // 書籍列表
console.log(result.totalCount); // 總筆數
});3. 優勢
- 型別安全 (若搭配 TypeScript 生成)。
- 自動處理錯誤:若 API 回傳錯誤,ABP 的全域錯誤處理器會自動顯示 SweetAlert 通知,您不需要
try-catch。 - 自動參數序列化。
12.4 頁面模型 (Page Models) 與 MVVM
在 Razor Pages 中,我們推薦使用 PageModel 作為 ViewModel。
1. 定義 PageModel
public class IndexModel : BookStorePageModel
{
private readonly IBookAppService _bookAppService;
[BindProperty(SupportsGet = true)]
public int CurrentPage { get; set; } = 1;
public PagedResultDto<BookDto> BookResult { get; set; }
public IndexModel(IBookAppService bookAppService)
{
_bookAppService = bookAppService;
}
public async Task OnGetAsync()
{
BookResult = await _bookAppService.GetListAsync(new GetBooksInput
{
SkipCount = (CurrentPage - 1) * 10,
MaxResultCount = 10
});
}
}2. 繼承基類
繼承 AbpPageModel (或專案生成的 BookStorePageModel) 可以獲得:
L["Key"]:本地化字串簡寫。CurrentUser:當前登入使用者。ObjectMapper:物件映射。
12.5 主題系統 (Theming)
ABP 的 UI 是基於主題系統的。這意味著您可以切換主題而無需修改 Razor 視圖。
1. 基本主題 (Basic Theme)
社群版預設使用 Basic Theme,基於 Bootstrap 5。
- Layout: 定義了頁首、頁尾、選單。
- Components: 定義了 Alert, Button 等樣式。
2. 自訂主題
您可以透過覆寫 .cshtml 檔案來自訂主題。
- 例如,建立
Themes/Basic/Layouts/Application.cshtml來替換預設的 Layout。
12.6 實戰練習
練習 1:使用 Tag Helpers 建立表單
- 建立一個
CreateModal.cshtml。 - 使用
abp-input為CreateBookDto的每個屬性建立輸入框。 - 使用
abp-modal包裝整個表單。
練習 2:JavaScript API 呼叫
- 在
Index.js中,使用volo.bookStore.books.book.create來送出表單。 - 成功後,使用
abp.notify.success顯示成功訊息,並重新載入表格。
練習 3:實作分頁
- 在
IndexModel中處理分頁參數。 - 在
Index.cshtml中使用abp-paginator顯示分頁控制項。
12.7 總結
ABP 的 MVC/Razor Pages 支援讓傳統的 Web 開發變得現代化且高效。
- Tag Helpers 減少了 HTML 雜訊。
- JS Proxies 簡化了前後端互動。
- Theme System 提供了統一的視覺風格。
下一章,我們將探討 Blazor WebAssembly,看看 ABP 如何支援這種新興的前端技術。
參考資源: