前言
ABP Framework 的 Template 方案,是依 Domain-Driven Design (DDD) 原則去實現分層應用,
但是為什麼它所建立出來的方案中會多出許多的專案呢?
以下就讓我們來了解一番 ^_^
研究
Domain-Driven Design (DDD) 常見到的就是以下的圖,
基本的 DDD Web 系統
所以 DDD 的 Web 系統基本上會建立 4 個專案(以 ProductManagement 為例),
1.Domain
包含 business object 及 Repository interface ,例如 Product class (aggregate root entity), IProductRepository interface
2.Application
參考 Domain 專案,建立 Service class 利用 Repository interface 來操作 business object,例如 ProductAppService class 中透過 IProductRepository interface 針對 Product class 進行 CRUD
3.Infrastructure
參考 Domain 專案,實作 Repository interface,進行實際的資料操作
4.Web
參考 Application 專案,建立 UI 提供使用者使用,透過 Application 的 Service 來進行各項操作。
執行時 Application 需要 Infrastructure 去存取資料庫。
所以各專案的關連就如下圖,
ABP Framework 的 Template 方案
當我們透過 ABP CLI 來建立方案時,會有以下幾個專案,
1 | mkdir ProductManagement |
ABP 存取資料庫是使用 EntityFrameworkCore 所以它會對應到 Infrastructure 專案。
但如果只有這 4 個專案會有一個問題,
就是 Web 專案會間接參考到 Domain 專案 (透過 Application 專案),
就沒達到分層的意義。
所以 ABP template 就將 application layer 分成 2 個專案,
1.Application.Contracts
定義 application service interface 及相關的 DTOs ,例如 IProductAppService interface 及 ProductCreationDto class
2.Application
實作 Application.Contracts 專案定義的 service interface,例如 ProductAppService 實作 IProductAppService
所以,Web 專案原本是參考 Application 專案 及間接參考到 Domain 專案,
會改成參考 Application.Contracts 專案,也不會再間接參考到 Domain 專案,
透過 Application.Contracts 中的 service interface 來進行各項的操作,
而原本需要使用到的 business object 則改使用 DTOs。
當然,在執行時,還是會使用實作 interface 的 Application 專案及 EntityFrameworkCore 專案。
但在實際上,可能想要重用 Domain 專案中的一些類別或是數值的定義,
例如 ProductType enum 或是 產品名稱最大長度。
這些都是一樣的,不想重覆在 Domain 專案及 ApplicationContracts 專案之中。
所以 ABP template 就再多一個 Domain.Shared 專案,來放這些共用的 type 及 常數。
到這裡,ABP template 各專案的關連就如下圖,
但是,ABP template 方案中,還有其他的專案,它們又是做什麼的呢?
1.HttpApi
使用 ABP 的 Auto API Controllers 功能,依 Application.Contracts 專案中定義的 service interface 自動建立 API Controller
2.HttpApi.Client
使用 ABP 的 Dynamic C# API Clients 功能,封裝 Application.Contracts 專案中定義的 service interface ,讓 application 或是其他 .NET client 可以很容易的使用,它則會自動去 call 我們的 HTTP API,並 Handle Retry,不需要我們自已去建立 HttpClient 呼叫 API
加進 HttpApi 及 HttpApi.Client,ABP template 各專案的關連就如下圖,
3.DbMigrator
參考 Application.Contracts 專案及 EntityFrameworkCore 專案,來建立資料庫(如果需要),執行 database migrations 及 seeds initial data(如果需要)的 Console 程式
但是查看 Web 專案,為什麼它的專案相依性卻是 Application 專案 及 EntityFrameworkCore 專案呢?
雖然在整個 Web 專案的 Page 程式中並沒有使用到,
但因為 Web 專案在執行時,需要 Application 專案 及 EntityFrameworkCore 專案,
所以才將它們加入參考。
當然,如果覺得這樣子不 OK, Web 專案應該只需要參考 Application.Contracts 專案。
則可以參考 SeparateHosting example ,新增一個 Web.Host 的專案,加入執行時需要的 Application 專案、 EntityFrameworkCore 專案、 HttpApi 專案及 Web 專案參考,而 Web 專案則改只參考 Application.Contracts 專案。
參考資料
Application Startup Template
Onion Architecture Is Interesting
ABP SeparateHosting example