1.前言
我是2012年就注冊了博客園賬號,后來之前的賬號在一次事故中被注銷了,又注冊了新的賬號,來博客園8年時間 我沒有發布過一篇博文,非常的慚愧,一直在默默的跟着大佬們學習.net技術。今天我也要回饋一下園子里的小伙伴,把我搭建的一套DDD框架分享出來,分享的目的是幫助一些小伙伴們學習.net core 的基本知識和領域驅動設計的要點。再次聲明領域驅動設計的核心是領域的划分已經領域的建模,領域驅動的思想遠比代碼重要。框架的搭建參考了微軟 eshoponcontainers、 Equinox .
2.框架分層
1.Ocean.API 着一層不用多解釋 web api 應用負責提供前端通訊接口。
2.Ocean.Application 應用層 主要負責解析前端的ViewDto 、中轉指令、實現查詢。
3.Ocean.Domain 核心領域層 主要實現領域事件 領域模型 請求指令等。
4.Ocean.Domain.Core 領域層輔助 主要實現一些 輔助領域層的類,比如倉儲接口、值對象、BaseEntity、聚合跟等。
5.Ocean.Infrastructure 基礎設施層 主要負責實現倉儲接口、事件溯源、等
3.工具以及第三方工具
准備工具
Visual Studio Community 2019、SQLService
第三方程序包
ASP.NET WebApi Core 主應用程序
Entity Framework Core 3.1 數據操作 主要完成命令操作
Dapper 數據操作 主要完成數據查詢
AutoMapper 實體映射 主要完成 ViewDto 到 domain Model 轉換
FluentValidator 實體驗證負責前端ViewDto的驗證相關。
MediatR 事件發布 訂閱 推送 實現 領域事件 CQRS 讀寫分離
Swagger UI 接口展示供前端查看
AutoFac DI容器 依賴注入
serilog 日志記錄
Identity.JWT 身份驗證
4.以領域驅動視角介紹框架
CQRS 命令查詢職責分離我的理解就是 把查詢和命令分開實現。利於分類管理
通過圖上可以看出 在Service中 我們直接實現了查詢的功能,如果是其他的 增刪改操作 通過發送指令轉到指令代碼中去實現,說真的這個還不是很完美的CQRS,我覺得發送指令這一步應該直接在Controller 中發送。查詢的操作使用了Dapper 很方便,最開始博主想用一個Dapper拓展使用 linq 表達式簡化SQL 后來想了一下 還是直接寫SQL 更加直觀。
上面三張圖片展示了Command所在的位子,命令其實也是為了領域模型服務的,所以他是領域模型的一部分,RegisterCommand我個人認為其實是一個參數傳遞的實體,負責給命令處理程序(UserHandle)傳遞信息。在Handle中 我們真正實現 增刪改的業務邏輯。
領域划分我個人理解就是把我們業務中的模塊歸類,比如 發布博客、購買商品等,在我們的程序中就是建立相對的實體類確定聚合根。
領域事件 是在領域模型完成本職操作之后的副作用 比如 發布博客之后發用郵件通知關注你的用戶 等。
上圖中 左邊我畫出了我實現的幾個領域模型 user Role 都是聚合根。右變的圖展示了 User聚合根中實現的功能。所有模型類采用充血模型,充血模型就是把領域中的操作放在領域中。大家注意 this.AddDomainEvent(registedUserEvent); 這句話 就是 當用戶注冊完成之后發送領域事件 去完成之后的操作。稍后還會將這里的實現。
每一個領域模型都繼承BaseEntity,在BaseEntity中 有關於領域事件的操作,AddDomainEvent方法只是把所有的要執行的領域事件放到集合中,然后在EF提交的時候統一執行領域事件,這個設計我覺得非常的棒,是我在微軟的 eshoping 項目中搬運過來的。
事件溯源 記錄每一次領域事件的上下文,用來追蹤一個領域模型的每一個動作。
InEventBus被稱為事件總線,負責發布事件的時候集成一些業務,這里就在推送事件的時候把事件的上下文記錄下來(_eventStore?.Save(@event))被曾為事件溯源。
最后總結
我承認我的博客寫的很懶,對領域設計的講解也牛頭不對馬嘴,大家還是看代碼學習把,在吐槽一下寫博客真的很累,我以后也需要好好學習寫文章的技巧,怎么才能把我的想法,技術轉化文字闡述給大家,在這里致敬每一個堅持寫博客的博主,是你們的堅持讓我們更加認識代碼的世界。