【IT 架構筆記 005】ABP Framework + Blazor Server:企業級 ERP 系統的分層架構實踐

【IT 架構筆記 005】ABP Framework + Blazor Server:企業級 ERP 系統的分層架構實踐

以 ABP Framework 為基礎,搭配 Blazor Server 前端與 Entity Framework Core,實踐 DDD 領域驅動設計的企業級 ERP 系統架構。本文拆解各層職責、技術選型理由,以及與傳統 MVC 架構的差異比較。


在建構企業級製造業 ERP 系統時,技術架構的選型攸關系統的長期可維護性與擴充性。本文記錄一套以 ABP Framework 8.x + Blazor Server + Entity Framework Core 為核心的實戰架構,並深入解析為何採用 DDD 分層設計,以及各層的實際職責。


.NET 網頁技術發展史

在理解現代架構之前,先看 .NET 網頁技術走過的路:

年代技術模式特色
2002ASP.NET WebForms事件驅動類似 VB 的拖拉控制項,Button、GridView、事件雙擊寫邏輯,畫面與邏輯混在一起
2009ASP.NET MVCMVC 三層畫面(View)、邏輯(Controller)、資料(Model)明確分離,Razor 語法撰寫 HTML
2012ASP.NET Web APIRESTful API純後端 API,前端改用 JavaScript 框架(jQuery、AngularJS)呼叫
2016ASP.NET Core MVC跨平台 MVC重寫為跨平台版本,支援 Linux 部署,效能大幅提升
2019Blazor Server元件化C# 取代 JavaScript,畫面邏輯透過 SignalR 在伺服器執行,瀏覽器只收 HTML
2020Blazor WebAssembly元件化C# 編譯為 WebAssembly 直接在瀏覽器執行,不需要伺服器即時連線
現在ABP + Blazor ServerDDD 分層企業級框架封裝多租戶、權限、稽核,搭配 Blazor 前端全 C# 開發

核心演進脈絡:

  • WebForms → MVC:從「拖拉控制項」走向「程式碼明確分層」
  • MVC → Web API + JS 前端:前後端徹底分離,各自獨立部署
  • Web API → Blazor:把 JavaScript 換回 C#,統一語言降低切換成本
  • Blazor → ABP + Blazor:在 Blazor 之上加企業級框架,解決多租戶、權限等共通需求

技術棧總覽

層次技術版本
前端框架Blazor Server.NET 8
UI 元件庫Ant Design Blazor1.6.x
後端框架ABP Framework8.3.x
ORMEntity Framework Core8.x
資料庫SQL Server2022
認證授權OpenIddict內建於 ABP
主題LeptonX LiteABP 官方
部署環境Windows Server + IIS-

為什麼選擇 ABP Framework

ABP Framework 是 .NET 生態系中最完整的企業級應用框架,它內建解決了大多數企業系統都需要處理的橫切關注點:

  • 多租戶(Multi-tenancy):同一套系統供多個工廠/子公司使用,資料完全隔離
  • 權限管理:細粒度的功能權限定義與檢查,內建 UI 管理介面
  • 稽核日誌:自動記錄誰、何時、對哪筆資料做了什麼變更
  • 模組化:業務功能可以獨立成模組,各自擁有完整的分層結構

對於需要對接多個外部系統(ERP、WMS、簽核引擎)的製造業系統,這些能力若從零實作需耗費大量時間,ABP 讓團隊可以聚焦在業務邏輯本身。


DDD 分層架構詳解

ABP Framework 強制採用 Domain-Driven Design(DDD,領域驅動設計) 的分層架構。整個解決方案由以下幾層構成:

第一層:Domain Layer(領域層)

這是整個系統最核心的一層,定義業務實體與業務規則。

// 以訂單主檔為例
public class OrdHeader : FullAuditedAggregateRoot<Guid>, IMultiTenant, IMustHavePlant
{
    public string OrderNo { get; set; }
    public string Status { get; set; } = "Draft";
    public DateTime DeliveryDate { get; set; }
    public ICollection<OrdLine> Lines { get; set; } = new List<OrdLine>();
}

關鍵概念:

  • AggregateRoot:聚合根,代表一個完整的業務概念(一張訂單 + 其所有明細)
  • FullAudited:ABP 自動注入建立時間、建立者、修改時間、修改者、軟刪除
  • IMultiTenant:自動過濾資料,每個租戶只看得到自己的訂單
  • IMustHavePlant:自訂介面,強制每筆資料標記所屬工廠

Domain.Shared 子層存放常數、列舉與跨層共用的基礎定義,不依賴任何其他層。

第二層:Application.Contracts Layer(應用合約層)

定義「系統能做什麼」的公開介面,是畫面與邏輯之間的合約。

public interface IOrdHeaderAppService :
    ICreateUpdateAppService<OrdHeaderDto, Guid, CreateUpdateOrdHeaderDto>
{
    Task<PagedResultDto<OrdHeaderDto>> GetListAsync(OrdHeaderListInput input);
    Task ConfirmAsync(Guid id);
}

這一層只有介面與 DTO(Data Transfer Object),沒有任何實作邏輯。好處是 UI 層只依賴介面,未來實作可以替換而不影響畫面。

第三層:Application Layer(應用服務層)

實作 Contracts 定義的介面,負責編排業務流程。

public class aaaAppService : AppService, aaaAppService
{
    public async Task ConfirmAsync(Guid id)
    {
        await AuthorizationService.CheckAsync(OrdersPermissions.Confirm);
        var order = await _repository.GetAsync(id);
        order.Status = "Confirmed";
        order.ConfirmDate = Clock.Now;
        await _repository.UpdateAsync(order);
    }
}

這層的職責:驗證權限、呼叫 Domain 層、協調多個服務、觸發事件。不包含資料庫細節,也不包含畫面細節。

第四層:EntityFrameworkCore Layer(基礎建設層)

將 Domain 實體映射到資料庫資料表,處理所有持久化細節。

builder.Entity<OrdHeader>(b =>
{
    b.ToTable("OrdHeaders");
    b.Property(x => x.OrderNo).IsRequired().HasMaxLength(30);
    b.HasMany(x => x.Lines).WithOne().HasForeignKey(x => x.HeaderId);
});

當 Domain 層的實體新增欄位時,這層產生 Migration 自動更新資料表結構,不需要手寫 SQL。

第五層:Blazor Server UI Layer(展示層)

使用 Razor Component 撰寫畫面,透過注入的 AppService 介面與後端溝通。

@inject IOrdHeaderAppService OrderService

@code {
    private List<OrdHeaderDto> _items = new();

    protected override async Task OnInitializedAsync()
    {
        var result = await OrderService.GetListAsync(new OrdHeaderListInput());
        _items = result.Items.ToList();
    }
}

畫面只認識介面(IOrdHeaderAppService),完全不知道底層資料庫是 SQL Server 還是其他資料庫。


模組化設計

除了主應用程式的分層外,複雜的業務領域被拆分為獨立模組,每個模組擁有完整的四層結構:

modules/
├── Orders/           ← 訂單模組
│   ├── Domain/
│   ├── Domain.Shared/
│   ├── Application.Contracts/
│   └── EntityFrameworkCore/
└── stock/            ← 庫存模組

模組的應用服務實作統一放在主應用程式的 Application 層,讓跨模組的業務邏輯可以互相呼叫,同時保持模組定義的獨立性。


Blazor Server vs 傳統前後端分離

採用 Blazor Server 而非 React + API 的關鍵考量:

考量點Blazor ServerReact + API
語言統一前後端皆為 C#前端 JS,後端 C#
即時互動SignalR 自動處理需自行實作 WebSocket
ABP 整合官方完整支援需額外整合
適用場景內部系統、固定網路環境對外系統、行動裝置
人才市場較少較多

對於使用者在公司內網操作的企業內部系統,Blazor Server 的 SignalR 連線穩定性足夠,且省去維護兩套語言與 API 文件的成本。


部署架構

開發者本機
    ↓ git push(內網 Bonobo Git Server)
Windows Server
    ├── IIS(aaa_prod / aaa_test 兩個站台)
    ├── dotnet publish -c Release
    └── 設定檔分離:appsettings.json(版控)+ appsettings.secrets.json(不版控)

設定檔採雙層設計:一般設定進版控,含密碼的 secrets 檔案僅存於各環境伺服器,不進入 Git。


多新增一個功能需要改幾個地方

這是 DDD 分層架構最常被詢問的問題。以新增一個欄位為例:

步驟檔案說明
1Domain/Entities/OrdHeader.cs新增屬性
2Application.Contracts/Dto/OrdHeaderDto.csDTO 對應
3EntityFrameworkCore Migration資料表新增欄位
4Application/OrdHeaderAppService.cs業務邏輯調整(如需要)
5Blazor/Pages/Orders/OrderEdit.razor畫面新增輸入框

五個地方看似繁瑣,但每個地方職責單一、邏輯清晰。相較於在一個大檔案裡混雜所有邏輯,長期維護成本反而更低。


小結

ABP Framework + Blazor Server 的組合,本質上是用較高的初始架構複雜度換取長期的可維護性與擴充性。對於業務規則複雜、需要對接多個外部系統、有多租戶需求的企業內部系統,這套架構提供了一個清晰的邊界與規範,讓團隊在系統規模成長後仍然能夠有序地擴展功能。

若是小型內部工具或快速驗證的原型,則可考慮 ABP 的 App No Layers 範本,以更少的分層換取更快的開發速度。


參考資源

官方文件

資源說明
ABP Framework 官網框架文件、教學、範本
ABP GitHub原始碼,12k+ stars
ABP DDD 指南DDD 分層設計官方說明
Blazor Server 文件Microsoft 官方 Blazor 文件
Ant Design BlazorUI 元件庫文件

值得參考的 GitHub 專案

專案技術棧說明
ant-design-blazor-abpABP + Blazor + Ant Design與本文架構完全一致的範本專案
abpframework/abpABP Framework框架本體,含 BookStore 教學範例
EasyAbp/awesome-abpABP 生態系社群整理的模組與資源清單