回顧:NLayerAppV3是一個使用.net 2.1實作的經典DDD的分層架構的項目。
NLayerAppV3是在NLayerAppV2的基礎上,使用.net core2.1進行重新建構的;它包含了開發人員和架構師都可以重用的DDD層。
Github位址:https://github.com/cesarcastrocuba/nlayerappv3
NLayerAppV3的基礎結構層一共分為兩個部分。處理資料相關的基礎元件和Cross-Cutting的基礎元件。
處理資料相關的基礎元件主要包含UOW和倉儲的實作;
Cross-Cutting的基礎元件目前主要包含資料擴充卡、國際化、驗證;
本篇介紹NLayerAppV3的Infrastructure(基礎結構層)的Data部分和Application(應用層)
1、Infrastructure(基礎結構層)的Data部分
Data部分是處理資料相關的基礎元件主要包含UOW和倉儲的實作。
UOW的實作:BaseContext繼承了DbContext和IQueryableUnitOfWork
DbContext是EF Core資料庫上下文,包Microsoft.EntityFrameworkCore
IQueryableUnitOfWork繼承IUnitOfWork和ISql,是EF Core方式的契約定義
Isql定義了支援sql語句的方式
Repository倉儲的層超類型,通過構造函數注入了IQueryableUnitOfWork和ILogger,定義了EF Core方式的CURD以及查詢過濾,包括分頁等行為
MainBCUnitOfWork實作了BaseContext。示例使用記憶體資料庫的方式來示範,當然,根據實際需要,可以很容易地擴充使用sqlserver、mysql、sqlite等,這也符合了開閉原則
BankAccountRepository是BankAccount倉儲,繼承Repository<BankAccount>,IBankAccountRepository,通過構造函數注入了MainBCUnitOfWork和ILogger,提供了一個GetAll方法,用來擷取BankAccount的集合。
public class BankAccountRepository
:Repository<BankAccount>,IBankAccountRepository
{
#region Constructor
/// <summary>
/// Create a new instance
/// </summary>
/// <param name="unitOfWork">Associated unit of work</param>
/// <param name="logger">Logger</param>
public BankAccountRepository(MainBCUnitOfWork unitOfWork,
ILogger<Repository<BankAccount>> logger)
: base(unitOfWork, logger)
{
}
#endregion
#region Overrides
/// <summary>
/// Get all bank accounts and the customer information
/// </summary>
/// <returns>Enumerable collection of bank accounts</returns>
public override IEnumerable<BankAccount> GetAll()
{
var currentUnitOfWork = this.UnitOfWork as MainBCUnitOfWork;
var set = currentUnitOfWork.CreateSet<BankAccount>();
return set.Include(ba => ba.Customer)
.AsEnumerable();
}
#endregion
}
View Code
2、Application(應用層)
協調領域模型與其它應用、包括事務排程、UOW、資料轉換等。
IService定義了應用層服務的契約。Service實作了IService,通過構造函數注入IRepository,為什麼要注入IRepository?
因為要擷取實體的相關資訊,就必須通過倉儲去操作聚合,而聚合是通過聚合根跟外部聯系的。
ProjectionsExtensionMethods作用是使用擴充方法,将實體轉換為DTO或者将實體集合轉換為DTO的集合
IBankAppService定義了Bank的應用層契約。有開戶、查找賬戶、鎖定賬戶、查找賬戶活動集、轉賬等業務。
BankAppService實作了IBankAppService。通過構造函數注入IBankAccountRepository、ICustomerRepository、IBankTransferService、ILogger。
IBankAccountRepository是BankAccount的倉儲契約;
ICustomerRepository是Customer使用者的倉儲契約;
IBankTransferService是轉賬的領域服務;
轉賬方法的代碼:
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
Application.MainBoundedContext.DTO項目
項目中是所有的DTO對象和使用AutoMapper轉換的配置轉換規則的Profile檔案。
這裡的Profile檔案是在Infrastructure(基礎設施層)Crosscutting部分的Adapter(擴充卡)中AutomapperTypeAdapterFactory(AutoMapper的類型轉換器建立工廠)建立AutomapperTypeAdapter(AutoMapper的類型轉換器)時使用反射的方式調用的。