建議大家研究一下ABP預構建模塊源代,了解它們是如何在應用中構建和使用的,因為這樣你可以看到模塊化開發的實現細節。
本節探討的支付模塊,是一個簡單而又真實的案例,特別是當你的應用想要升級到高級帳戶時,您可以使用它來接收付款。
這里不會展示該模塊的開發步驟,只研究基本要點,以便您了解模塊結構并構建自己的模塊。
## 創建新應用模塊
我們使用 ABP CLI 命令行工具創建新解決方案:
```
abp new Payment -t module
```
`-t module` 指定創建的是模塊,模塊名是`Payment`。打開解決方案,如下圖所示:

啟動模板有太多的項目,因為它支持多個UI和數據庫選項,并且包含一些測試/演示項目,我們需要做篩選,刪除不必要的項目:
我們把`src`文件夾中需要的項目留下來,然后刪除以下項目:
* 刪除了Blazor.\*的項目,因為采用的是MVC/Razor頁面。
* 刪除了與MongoDB相關的項目,因為這里使用的是EF Core模塊。
* 最后,刪除了angular文件夾,因為不希望這個模塊有angular UI。
清理之后,解決方案中有12個項目。其中4個用于單元和集成測試,剩下8個主模塊。

這8個項目是類庫項目,因此不能單獨運行。它們需要由可執行應用程序使用,例如EventHub。
重新整理后的支付模塊的結構和層次已在第9章DDD部分介紹過了,不再重復。
下面我們將進一步演化這種結構,因為我們希望為支付模塊提供多個應用層。
## 重組支付模塊解決方案
我們將把裁剪過的支付模塊安裝到EventHub解決方案中。我們回顧第4章,知道EventHub解決方案有兩個UI應用程序:

* 主站:最終用戶用于創建和參加活動的公共網站,這個應用程序有一個MVC/Razor頁面UI。
* 后臺:系統管理員使用的后臺程序。是由Blazor WebAssembly構建。
為了支持相同的架構,我們將為支付模塊提供兩個UI應用層:
* 帶有MVC/Razor Pages UI的應用層,由EventHub主站使用。最終用戶將使用該UI付款。
* 帶有Blazor WebAssembly UI的應用層,由EventHub管理后臺使用。管理用戶將通過該UI查看付款報告。
下圖展示重組后的最終支付解決方案:

admin端,我添加了`Payment.Admin.Application`,?`Payment.Admin.Application.Contracts`,?`Payment.Admin.Blazor`,?`Payment.Admin.HttpApi`, 和`Payment.Admin.HttpApi.Client`
我還加了`Payment.BackgroundServices` 項目定期進行一些后臺定時作用。
總體結構:后臺應用(Blazor UI)和公共主站應用(MVC/Razor UI)。這兩個應用共享相同的領域層和數據庫集成代碼。
我們了解了支付解決方案的總體結構,下面將介紹付款流程的細節。
## 支付流程
支付模塊的職責是向用戶提供支付服務,它在內部使用PayPal作為支付網關。支付模塊是通用的,可以被任何類型的應用程序使用。支付模塊應該包括一些啟動支付流程和處理支付結果的集成邏輯。
EventHub使用付款模塊從用戶處獲得付款,付款后的用戶將升級為高級用戶。所以高級用戶在應用中會擁有更多權限。
如果您是組織的所有者,并訪問了組織詳細信息頁面,您將在頁面上看到升級到高級按鈕,如下圖所示

單擊“升級到高級”按鈕時,您將被重定向到定價頁面:

在這里,我們可以看到賬戶類型及其差異。單擊此處的“升級到高級”按鈕時,我們將被重定向到預結賬頁面,該頁面由支付模塊定義:

預結賬頁面通常位于支付模塊內部,并且開發為獨立于應用的頁面。我們可以使用`/Payment/PreCheckout?paymentRequestId=3a002186-cb04-eb46-7310-251e45fc6aed`URL將用戶重定向到預簽出頁面
但是,我們應該首先使用IPaymentRequestAppService服務的CreateAsync方法獲取支付請求ID。這在`EventHub.Web`項目的`Pages/Pricing.cshtml.cs`頁面中完成。
EventHub應用覆寫了視圖(UI)部分,使其更好地適應EventHub的UI設計。
這是一個在最終應用中自定義模塊的示例。EventHub應用在`Pages/Payment`文件夾下定義了`PreCheckout.cshtml`?和`PostCheckout.cshtml`,如下圖所示:

它們會自動覆蓋相應的支付頁面(因為它們完全位于支付模塊定義的同一路徑中)。這些頁面沒有`.cshtml.cs`文件,因為我們不想改變頁面的邏輯行為,我們只是想改變一下界面展示。
下圖顯示了支付的主要組件和流程:

* 一旦在付款界面我們點擊升級按鈕,它會跳轉到支付模塊的確認頁面(Checkout),當我們點擊確認按鈕,我們將跳轉到PayPal。
* 支付模塊整合了支付系統,一旦我們在PayPal上完成付款,我們將被重定向回應用的結賬后頁面,該頁面將向用戶顯示感謝信息。
* 當支付過程成功時,支付模塊將發布一個分布式事件`PaymentRequestCompletedEto`?(定義?在`Payment.Domain.Shared`?項目中)。
EventHub應用通過`PaymentRequestEventHandler`?類訂閱上面的事件(定義在`EventHub.Domain`項目中),它會找到已完成付款的用戶和組織,升級組織,并發送電子郵件感謝用戶升級帳戶。
* 在一些罕見的情況下,從PayPal返回時可能會出現錯誤,我們無法知道支付過程是否成功。對于這種情況,支付模塊提供了一個回調,PayPal會調用該回調來通知我們支付操作的狀態。回調請求由`PaymentRequestController`(在`Payment.HttpApi`項目中)處理。如果操作成功,將發布相同的`PaymentRequestCompletedEto`事件,以便EventHub應用可以異步升級組織帳戶。
接下來,我們將介紹支付模塊如何提供配置選項。
## 提供配置選項
支付模塊使用PayPal,因此必須配置的PayPal帳戶信息。它遵循選項模式(詳情參閱第5章的實現選項模式),并提供`PayPalOptions`類,如以下示例所示:
```
Configure(options => {
options.ClientId = "..."; ????
options.Secret = "...";
});
```
我們通常從配置文件(`appsettings.json`)中獲取值。付款模塊可以由`Payment:PayPal`鍵獲取選項值,如下例所示:
```
"Payment":
{
"PayPal":
{
"ClientId": "...",
"Secret": "...",
"Environment": "Sandbox"
}
}
```
在`Payment.Domain`項目的`PaymentDomainModule`類中配置如下:
```
Configure<PayPalOptions>(configuration.GetSection("Payment:PayPal"));
```
默認,從配置中獲取值是一種良好的做法。
我已經介紹了支付模塊結構的要點。它的代碼與典型的ABP應用沒有太大區別。您可以下載源碼,了解它的內部工作原理。
- 前言
- 第一部分
- 第1章 現代軟件開發和 ABP 框架
- 企業級 Web 開發的挑戰
- ABP框架的能力清單
- 第2章 ABP框架入門
- 安裝 ABP CLI
- 創建新解決方案
- 運行解決方案
- 探索預構建模塊
- 第3章 逐步開發開發ABP應用
- 創建解決方案
- 定義領域對象
- EFCore和數據庫映射
- 定義應用服務
- 測試產品
- 產品列表
- 創建產品
- 編輯產品
- 刪除產品
- 第4章 探索 EventHub解決方案
- 應用介紹
- 架構探索
- 方案運行
- 第二部分
- 第5章 探索ABP基礎架構
- 了解模塊化
- 使用依賴注入系統
- 配置應用程序
- 實現選項模式
- 日志系統
- 第6章 數據訪問基礎架構
- 定義實體
- 定義倉儲庫
- EF Core集成
- 了解 UoW
- 第7章 探索橫切關注點
- 認證授權
- 用戶驗證
- 異常處理
- 第8章 體驗 ABP 的功能和服務
- 獲取當前用戶
- 使用數據過濾
- 控制審計日志
- 緩存數據
- 本地化用戶界面
- 第三部分
- 第9章 理解領域驅動設計
- 介紹 DDD
- 構建基于 DDD 的 解決方案
- 處理多個應用程序
- 了解執行流程
- DDD的通用原則
- 第10章 領域層 Domain
- 領域事件案例分析
- 聚合和實體的設計原則和實踐
- 實現領域服務
- 落地存儲庫
- 構建規約(Specification)
- 領域事件
- 第11章 應用層 Application
- 落地應用服務
- 設計 DTO
- 理解各層的職責
- 第四部分
- 第12章 MVC/Razor 頁面
- 主題系統
- 綁定和壓縮
- 導航菜單
- Bootstrap標簽助手
- 創建表單并驗證
- 使用模態窗口
- 使用JS API
- 調用HTTP API
- 第13章 Blazor WebAssembly UI
- 什么是Blazor
- ABP Blazor UI
- 驗證用戶身份
- 理解主題系統
- 使用菜單
- 使用基本服務
- 使用UI服務
- 消費HTTP API
- 使用全局腳本和樣式
- 第14章 HTTP API 和實時服務
- 構建HTTP API
- 使用HTTP API
- 使用SignalR
- 第五部分
- 第15章 落地模塊化
- 理解模塊化
- 構建支付模塊
- 安裝模塊
- 第16章 實現多租戶
- 理解多租戶
- 多租戶基礎設施
- 使用功能系統
- 何時使用多租戶
- 第17章 構建自動化測試
- 了解ABP測試基礎設施
- 構建單元測試
- 構建集成測試