NLayerAppV3是一個使用.net 2.1實現的經典DDD的分層架構的項目。 ...
雖然每天的工作都是CURD、還是使用著傳統的三層架構、使用著.net Framework,但是這並不能影響我學習DDD和.net core。
總是希望軟體在應對複雜多變的場景時能夠游刃有餘,在解決問題時能夠多一種選擇。
很早就有關註大神dax.net的NLayerApp系列博文https://www.cnblogs.com/daxnet/category/304141.html
近期入坑.net core,看了進擊的辣條的文章Asp.Net Core微服務初體驗,很有收穫,感謝感謝。
抽時間讀了下NLayerAppV3項目的源碼,Github地址:https://github.com/cesarcastrocuba/nlayerappv3
分享下體會,希望相互交流學習,謝謝!
1、項目簡介
NLayerAppV3是一個使用.net 2.1實現的經典DDD的分層架構的項目。
NLayerAppV3是在NLayerAppV2的基礎上,使用.net core2.1進行重新構建的;它包含了開發人員和架構師都可以重用的DDD層;以銀行和博客上下文示例。
2、項目結構
放一張DDD風格架構l圖。主要分為四層:表現層、應用層、領域層和基礎結構層。
詳細的各層的含義可以查看dax.net的文章https://www.cnblogs.com/daxnet/archive/2011/05/10/2042095.html
1.1-Presentation(表現層)
系統和用戶的交互層。UI展示給終端用戶、收集用戶的反饋信息。
1.2-Distributed Services(分散式服務層)
為應用程式提供遠程訪問;如果是http協議,一般設計為WebApi。
1.2.1-Seedwork --DistributedServices.Seedwork
分散式服務的Controller、Filter等
1.2.2-MainBoundedContext
--DistributedServices.MainBoundedContext
以銀行的業務示例,構建上下文、對外提供WebApi服務,結合Swagger UI
--DistributedServices.MainBoundedContext.Tests
DistributedServices.MainBoundedContext的測試項目
1.2.3-BlogContext
--DistributedServices.BlogBoundedContext
以博客業務示例,構建上下文,對外提供WebApi服務,結合Swagger UI
--DistributedServices.BlogBoundedContext.Tests
DistributedServices.BlogBoundedContext項目的測試項目
1.3-Application(應用層)
協調領域模型與其它應用、包括事務調度、UOW、數據轉換等。
主要作用:通過倉儲來訪問持久層;對不同領域的數據組織整理;協調領域對象之間、領域對象與基礎層的協作關係;應用服務等
1.3.1-Seedwork --Application.Seedwork
應用層共用介面、實現的封裝
1.3.2-MainBoundedContext
--Application.MainBoundedContext
業務模塊的應用層服務介面和實現
--Application.MainBoundedContext.DTO
應用層業務模塊的數據轉換等
--Application.MainBoundedContext.Tests
Application.MainBoundedContext的測試項目
1.3.3-BlogBoundedContext
同1.3.2,不同的是業務換為博客業務
1.4-Domain(領域層)
展現業務/領域邏輯、業務處理狀態,以及實現業務規則,它同時也包含了領域對象的狀態信息。
1.4.1-Seedwork
--Domain.Seedwork
領域層實體基類、倉儲介面、UOW介面、值對象基類、規約等
--Domain.Seedwork.Tests
Domain.Seedwork的測試項目
1.4.2-MainBoundedContext
--Domain.MainBoundedContext
實體、值對象、領域服務、聚合根、聚合及工廠
--Domain.MainBoundedContext.Tests
Domain.MainBoundedContext的測試項目
1.4.3-BlogBoundedContext
同1.4.2 業務邏輯換成了博客
1.5-Infrastructure(基礎設施層)
1.5.1-Data
為應用程式的數據存取提供服務,它可以是應用程式本身的持久化機制,也可以是外部系統提供的數據訪問的Web Service等
--Infrastructure.Data.Seedwork
UOW的實現基類、倉儲的實現基類
--Infrastructure.Data.MainBoundedContext
UOW的實現、倉儲的實現
--Infrastructure.Data.MainBoundedContext.Tests
Infrastructure.Data.MainBoundedContext的測試項目
1.5.2-CrossCutting
該層提供了能被其它各層訪問的通用技術框架,比如異常捕獲與處理、日誌、認證、授權、驗證、跟蹤、監視、緩存等等。
--Infrastructure.Crosscutting
適配器、國際化、驗證等介面的封裝
--Infrastructure.Crosscutting.NetFramework
適配器、國際化、驗證等實現、國際化依賴的資源
--Infrastructure.Crosscutting.Tests
Infrastructure.Crosscutting的測試項目
3、示例
以DistributedServices.MainBoundedContext項目的BankAccounts的轉賬api示例,說明下我的理解
[HttpPut] public void PerformTransfer([FromBody]BankAccountDTO from, [FromBody]BankAccountDTO to, [FromBody]decimal amount) { _bankAppService.PerformBankTransfer(from, to, amount); }View Code
_bankAppService通過構造函數註入。
readonly IBankAppService _bankAppService; public BankAccounts(IBankAppService bankAppService) { _bankAppService = bankAppService; }View Code
IBankAppService是應用層的服務介面
對應的應用層有介面的實現BankAppService
public BankAppService(IBankAccountRepository bankAccountRepository, // the bank account repository dependency ICustomerRepository customerRepository, // the customer repository dependency IBankTransferService transferService, ILogger<BankAppService> logger) { //check preconditions if (bankAccountRepository == null) throw new ArgumentNullException("bankAccountRepository"); if (customerRepository == null) throw new ArgumentNullException("customerRepository"); if (transferService == null) throw new ArgumentNullException("trasferService"); _bankAccountRepository = bankAccountRepository; _customerRepository = customerRepository; _transferService = transferService; _logger = logger; _resources = LocalizationFactory.CreateLocalResources(); }View Code
BankAppService通過構造函數註入了領域層的銀行賬號倉儲IBankAccountRepository和客戶倉儲ICustomerRepository、轉賬服務等,全部依賴於介面。
public void PerformBankTransfer(BankAccountDTO fromAccount, BankAccountDTO toAccount, decimal amount) { //Application-Logic Process: // 1º Get Accounts objects from Repositories // 2º Start Transaction // 3º Call PerformTransfer method in Domain Service // 4º If no exceptions, commit the unit of work and complete transaction if (BankAccountHasIdentity(fromAccount) && BankAccountHasIdentity(toAccount)) { var source = _bankAccountRepository.Get(fromAccount.Id); var target = _bankAccountRepository.Get(toAccount.Id); if (source != null & target != null) // if all accounts exist { using (TransactionScope scope = new TransactionScope()) { //perform transfer _transferService.PerformTransfer(amount, source, target); //comit unit of work _bankAccountRepository.UnitOfWork.Commit(); //complete transaction scope.Complete(); } } else _logger.LogError(_resources.GetStringResource(LocalizationKeys.Application.error_CannotPerformTransferInvalidAccounts)); } else _logger.LogError(_resources.GetStringResource(LocalizationKeys.Application.error_CannotPerformTransferInvalidAccounts)); }View Code
實現轉賬的功能,輸入參數都是Dto對象,通過AutoMapper或者其它映射工具完成數據轉換;通過倉儲訪問聚合,獲取源和目標賬號信息、開啟事務,UOW提交轉賬操作。
DistributedServices.MainBoundedContext的StartUp中註冊IOC
倉儲、領域服務、應用層服務、適配器、國際化、驗證、Swagger UI等。
運行項目
在DistributedServices.MainBoundedContext目錄下打開cmd命令,輸入dotnet restore,完成之後,輸入dotnet run
運行結果:
4、想法和計劃
跟.net core microsoft結合
使用ocelot搭建服務網關、結合identityserver4實現授權認證;polly服務熔斷;限流;consul服務發現;Appolo配置中心;Skywalking追蹤結果。