ABP.IO 新手教學 No.02
本文為 ABP.IO WEB應用程式框架開發教學第 1 部分,說明如何創建服務端。
此開發教學相較上一篇 No.01 快速開始 比較複雜一些
第一次接觸還沒看過快速開始的建議先從上一篇先看
這篇理論上同樣著重在 .Net Core + EF Core 建立 API
前端框架 Angular 的實現不在本次重點會先快速帶過
系列文章索引
參考: [2021] ABP.IO WEB應用程式框架 新手教學 No.0 全篇索引
本篇會以官方文件 開發教學 為依據中文化並附圖加以說明的方式進行
Web應用程序開發教程 - 第一章:創建服務端
關於本教程
在本系列教程中,您將構建一個名稱Acme.BookStore的用於管理書籍及其作者列表的基於 ABP 的程序。是使用以下技術開發的:
Entity Framework Core 為ORM 提供程序。
MVC / Razor Pages做為 UI 框架。
本教程分為以下部分:
下載源碼
本教程根據你的UI和數據庫首選項有多個版本,我們準備了一個模型下載的源碼組件:
創建解決方案
在開始開發之前,請按照入門教程創建命名Acme.BookStore的新解決方案。
// 這邊我從 https://abp.io/get-started 使用以下選項建立

// 這邊可以不要勾最下面的選項,這邊只是我想要分開,但分開真正要跑需要有 Redis,可以安裝 docker 後執行, docker pull redis & docker run --name some-redis -d redis -p 6379:6379
// 因為專案預設會啟用 Redis,如果沒有可以先關閉,在 appsettings.json 中的 Redis 裡面加上 "IsEnabled": "true", 請參考 Redis 快取設定 說明文件

創建圖書實體
啟動模板中的領域層分為兩個項目:
Acme.BookStore.Domain.Shared包括可與客戶端共享的所有對象,枚舉或其他域相關。
BookType 枚舉 (Enum)
下面的項目所產生的BookType枚舉,在Acme.BookStore.Domain.Shared創建BookType。
// 如果有開發過 API 應該遇過給 client 的時候蠻常會用到實體的 enum ,因為 DDD 中領域不會開放給外部(Client),所以這類東西需要放在領域共用專案,方便到時候 DTO 可以直接使用。

Book 實體 (Entity)
在解決方案的領域層 (Acme.BookStore.Domain項目)中定義你的實體。
該應用程序的主要實體是Book 。在Acme.BookStore.Domain項目中創建一個Books文件夾並在其中添加了一個名稱Book的類,如下所示:
ABP為實體提供了兩個基本的基類:
AggregateRoot和Entity。 Aggregate Root是領域驅動設計概念一個。可以直接查詢和處理的根實體(請參閱實體文檔)。 // 同聚合內非根的一般實體可以用 BookCover :Entity<Guid>,因為同聚合內應該只有一個根,DDD不熟暫時不想用也可以直接照你原本開發方式全部用一般實體基類Entity<T>Book實體繼承了AuditedAggregateRoot,AuditedAggregateRoot類在AggregateRoot類的基礎上添加了一些審計屬性(CreationTime,CreatorId,LastModificationTime)。ABP框架自動為你管理這些屬性。 // 不用聚合根也不想那麼多審計屬性, ABP 也提供其他基類 ,比如:CreationAuditedEntity<TKey>,再少也可以只使用 ABP 提供的介面 ,例如:IHasCreationTime,優點是可以統一屬性名稱為CreationTimeGuid是Book實體的主鍵類型。 // 主鍵類型也可以自己改,例如:BookPage :Entity<long>,只是 ABP 推薦使用 Guid 就是了
// 這邊引用一下 ABP 審計基類 中關於實體中巡覽屬性的一段敘述給大家參考一下

最終的文件夾/文件結構應該如下所示:

將Book實體添加到DbContext中
EF Core 需要你將實體和DbContext建立關聯。最簡單的做法是在Acme.BookStore.EntityFrameworkCore項目的BookStoreDbContext類中添加DbSet屬性。如下所示:

將書實體映射到數據庫表
在Acme.BookStore.EntityFrameworkCore項目中打開BookStoreDbContextModelCreatingExtensions.cs文件,添加Book實體的映射代碼。最終類應為:

ConfigureByConvention()方法優雅的配置/歸屬的屬性,應始終對你所有的屬性使用它。BookStoreConsts包含用於表的架構和表前綴的常量值。你不一定需要使用它,但建議在單點控製表的前綴。 // 這是定義資料表名稱前綴,用來跟 Abp 開頭的表來做區分,方便辨識哪些是框架用的資料表,哪些是我們自己應用程式用的資料表,或自己定義不同前綴來分類自己的表, // 這邊建議統一定義在領域層的一個統一地方,預設是BookStoreConsts.cs,有其他需要共用的常量 (Const) 也可以繼續統一加在這裡,方便使用與管理。

添加數據遷移
啟動模板使用EF Core Code First Migrations創建和維護數據庫架構。我們應該創建一個新的遷移並應用到數據庫。
在Acme.BookStore.EntityFrameworkCore.DbMigrations目錄中打開命令行輸入以下命令:

它會添加新的遷移類到項目中:


添加附加數據 (SeedData)
// 在之後的 整合測試 章節會用到這份資料來做測試,雖然不是必須的流程,但這邊建議可以試著做一遍。
在*.Domain項目下創建派生IDataSeedContributor的類,並且拷貝以下代碼:
如果中數據庫沒有當前圖書,則使用
IRepository<Book, Guid>(默認為知識庫 )將兩本書插入數據庫。

更新數據庫
運行Acme.BookStore.DbMigrator應用程序來更新數據庫:

.DbMigrator 是一個開發使用程序,可以在開發和生產環境遷移數據庫和初始化數據。
// 預設連線字串指定的 DB Server 是 LocalDb (裝 VS 預設會有的開發用 DB),沒有了話需要到 appsettings.json 改連線字串到自己的DB,
// 執行完以上可以用SSMS連到 (LocalDb)\MSSQLLocalDB 看看剛剛建立出來的資料庫與表,確認資料是否有如我們預期正確新建出來
創建應用程序
應用程序層由兩個單獨的項目組成:
在本部分中,您將創建一個應用程序服務,使用 ABP 框架的CrudAppService基類來獲取、創建、更新和刪除書籍。
// 這邊教學是使用非常規(ABP內建CRUD)的應用服務基底類別,基本的可以參考上一篇 快速開始 的應用服務部分,
// 這邊主要是了解ABP如何簡化重複的CRUD程式碼,基本的可以不實作任何一行程式,只要定義DTO並繼承ABP的介面與基類就可以提供基本CRUD程作業
Book Dto
CrudAppService基類需要定義實體的基本DTO。在Acme.BookStore.Application.Contracts項目中創建一個名稱BookDto的 DTO 類:
DTO類被用來表示層和應用層 傳遞數據 。查看DTO 文檔查看更多信息。
為了在頁面上展示書籍信息,
BookDto被將書籍數據傳遞到顯示層。BookDto繼承自AuditedEntityDto<Guid>。跟上面定義的Book實體一樣具有一些審計屬性。 // 這邊為了用來做 CRUD,某些DTO可能需要繼承內鍵含有Id定義的基類,才能正常做Update與Delete,一般DTO則可以不用,可以參考 快速開始

在將書籍返回到表示層時,需要將Book實體轉換為BookDto對象。 AutoMapper庫可以在定義正確的映射時自動執行此轉換。
啟動模板配置了AutoMapper,因此你很適合在Acme.BookStore.Application項目的BookStoreApplicationAutoMapperProfile類中定義映射:
創建更新書Dto
在Acme.BookStore.Application.Contracts項目中創建一個名稱CreateUpdateBookDto的 DTO 類:
這個DTO類被用於在創建或更新書籍的時候從用戶界面獲取圖書信息。
它定義了數據註釋屬性(如
[Required])來定義屬性的驗證。DTO由ABP框架自動驗證。
就像上面BookDto一樣,創建一個從對像CreateUpdateBookDto到Book實體的映射,最後一個映射類如下:
圖書應用服務介面
下一步是應用程序定義接口,在Acme.BookStore.Application.Contracts項目中定義一個未知IBookAppService的接口:
框架定義應用程序服務的接口不是必需的 。但是,它被建議為最佳實踐。
ICrudAppService定義了常見的CRUD方法:GetAsync,GetListAsync,CreateAsync,UpdateAsync和DeleteAsync。 你可以從空的IApplicationService接口繼承並手動定義自己的方法(將在下一個領域中完成)。ICrudAppService有一些變體,你可以在每個方法中單獨使用 DTO,也可以分別單獨指定(例如使用不同的 DTO 進行創建和更新)。

圖書應用服務
在Acme.BookStore.Application項目中命名BookAppService的IBookAppService實現:
BookAppService繼承了CrudAppService<...>。它實現了ICrudAppService定義的 CRUD 方法。BookAppService注入IRepository <Book,Guid>,這是Book實體的默認。ABP自動為每個化根(或實體)創建默認。請參閱文檔BookAppService使用IObjectMapper將Book對象轉換為BookDto對象, 將CreateUpdateBookDto對象轉換為Book對象。 啟動模板使用AutoMapper庫作為對象映射提供程序。我們之前定義了映射,從而導致方向預期工作。

自動生成API控制器
通常你創建控制器以將應用程序服務公開為HTTP API 。因此允許瀏覽器或客戶端通過 AJAX 調用他們。
ABP可以自動為你的應用程序服務配置MVC API控制器。
Swagger 的用戶界面
啟動模板配置為使用Swashbuckle.AspNetCore運行swagger UI 。運行應用程序並在瀏覽器中輸入https://localhost:XXXX/swagger/ (用你自己的端口替換XXXX)作為URL。
你會看到一些內置的接口和Book接口,它們都是REST風格的:

Swagger 有一個很好的 UI 來測試 API。
你可以嘗試執行[GET] /api/app/bookAPI來獲取書籍列表,服務端會返回以下JSON結果:
這很酷,因為我們沒有寫任何代碼來創建 API 控制器,但是現在我們有了一個可以正常使用的 REST API!
下一章
請參閱教程的下一章。
ABP.IO WEB應用程式框架 新手教學 No.02 開發教學 Part 2 圖書列表頁面

PS5
ABP
回首頁
本文章從點部落遷移至 Writerside