Skip to content

第十二章: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 20Esbuild 建置系統以及 SSR (Server-Side Rendering),提供了更佳的效能與 SEO 支援。本章將專注於 MVC / Razor Pages。


12.2 ABP Tag Helpers

ABP 提供了一套強大的 Tag Helpers,讓您能用宣告式的方式撰寫 Bootstrap UI,而無需記憶繁瑣的 CSS 類別。

1. 基礎元件

html
<!-- 按鈕 -->
<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

html
<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。

html
<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 前端開發的殺手級功能。您不需要手寫 fetchaxios 呼叫,ABP 會自動為您的 Application Service 生成 JavaScript 函式。

1. 引用腳本

_Layout.cshtml 中,ABP 已經自動注入了:

html
<script src="/Abp/ServiceProxyScript"></script>

2. 呼叫 API

假設您有一個 BookAppService,包含 GetListAsync 方法。

javascript
// 命名空間對應 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

csharp
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 建立表單

  1. 建立一個 CreateModal.cshtml
  2. 使用 abp-inputCreateBookDto 的每個屬性建立輸入框。
  3. 使用 abp-modal 包裝整個表單。

練習 2:JavaScript API 呼叫

  1. Index.js 中,使用 volo.bookStore.books.book.create 來送出表單。
  2. 成功後,使用 abp.notify.success 顯示成功訊息,並重新載入表格。

練習 3:實作分頁

  1. IndexModel 中處理分頁參數。
  2. Index.cshtml 中使用 abp-paginator 顯示分頁控制項。

12.7 總結

ABP 的 MVC/Razor Pages 支援讓傳統的 Web 開發變得現代化且高效。

  • Tag Helpers 減少了 HTML 雜訊。
  • JS Proxies 簡化了前後端互動。
  • Theme System 提供了統一的視覺風格。

下一章,我們將探討 Blazor WebAssembly,看看 ABP 如何支援這種新興的前端技術。


參考資源

Released under the MIT License.