本文主要介紹了多應用層的問題,包括原因和實現。通過理解介紹瞭如何區分領域邏輯和應用邏輯,哪些是正確的實踐,哪些是不推薦的或者錯誤的實踐。
不知道你們是否會遇到一種情況,通過ABP構建了一個後端的API專案,剛開始是為Web端專案(比如,Vue)提供後端介面服務的,隨著專案的發展和業務的複雜,增加了行動端的App,或者公眾號、小程式等,這樣不僅要為Web端提供API服務,而且還需要為行動端的App,或者公眾號、小程式等提供API服務。這個場景就是多應用層的問題。也就是說你現在需要構建一個有多個應用程式的系統了:
由於業務的複雜性,每個應用系統都有自己的不同應用服務方法,不同的輸入和輸出DTO,不用的認證和授權規則等,所以如果把所有的業務邏輯都融入到一個應用系統中,就會讓系統更難開發、維護和測試,並導致潛在的Bug風險。因此,為每個應用程式建立單獨的應用層,並且它們都是用單個領域層來共用核心領域邏輯。為了更加具體的說明,為每種應用程式型別建立不同的.csproj專案:
通常,DDD中的業務邏輯包括領域邏輯和應用邏輯。領域邏輯由系統的核心領域規則組成,而應用程式邏輯實現特定於應用程式的用例。話雖這樣說,但是並不容易區分什麼是領域邏輯和應用邏輯。
下面通過在領域服務中建立Organization這個例子,來儘可能簡要說明:
public class OrganizationManager:DomainService
{
private readonly IRepository<Organization> _organizationRepository; //Organization的倉儲
private readonly ICurrentUser _currentUser; //當前使用者
private readonly IAuthorizationService _authorizationService; //Authorization的服務
private readonly IEmailSender _emailSender; //郵件傳送服務
// 公共建構函式,依賴注入
public OrganizationManager(IRepository<Organization> organizationRepository, ICurrentUser currentUser, IAuthorizationService authorizationService, IEmailSender emailSender)
{
_organizationRepository=organizationRepository;
_currentUser=currentUser;
_authorizationService=authorizationService;
_emailSender=emailSender;
}
// 建立一個新的組織
public async Task<Organization> CreateAsync(string name)
{
// 如果組織存在同名,那麼丟擲異常[正確]
if(await _organizationRepository.AnyAsync(x=>x.Name==name))
{
throw new BusinessException("IssueTracking:DuplicateOrganizationName");
}
// 檢查是否擁有建立的許可權[錯誤]
await _authorizationService.CheckAsync("OrganizationCreationPermission");
// 記錄⽇志[錯誤]
Logger.LogDebug($"Creating organization {name} by {_currentUser.UserName}");
// 建立一個新的組織
var organization = new Organization();
// 傳送郵件進行提醒[錯誤]
await _emailSender.SendAsync("[email protected]", "新組織", "新組織名稱:"+name);
// 返回一個組織範例
return organization;
}
}
public class OrganizationAppService:ApplicationService
{
private readonly OrganizationManager _organizationManager; //組織的領域服務
private readonly IPaymentService _paymentService; //支付服務
private readonly IEmailSender _emailSender; //郵件服務
// 公共建構函式,依賴注入
public OrganizaitonAppService(OrganizationManager organizationManager, IPaymentService paymentService, IEmailSender emailSender)
{
_organizationManager=organizationManager;
_paymentService=paymentService;
_emailSender=emailSender;
}
// 建立組織
[UnitOfWork][正確] //工作單元,用於提交事務
[Authorize("OrganizationCreationPermission")][正確]
public async Task<Organization> CreateAsync(CreateOrganizationDto input)
{
// ⽀付組織的費⽤[正確]
await _paymentService.ChargeAsync(CurrentUser.Id, GetOrganizationPrice());
// 通過領域服務,建立一個新的組織範例
var organization = await _organizationManager.CreateAsync(input.Name);
// 儲存和更新組織到資料庫中[正確]
await _organizationManager.InsertAsync(organization);
// 傳送提醒郵件[正確]
await _emailSender.SendAsync("[email protected]", "新組織", "新組織名稱:"+name);
//返回範例[錯誤]
return organization;
}
private double GetOrganizationPrice()
{
return 42;//Gets form somewhere...
}
}
應用服務層的輸入和輸出引數都是DTO,不能返回實體。至於為什麼不將支付放在領域服務中,只能說業務重要也不一定放在領域服務中,詳細原因說明參考[1]。
參考文獻:
[1]基於ABP Framework實現領域驅動設計:https://url39.ctfile.com/f/2501739-616007877-f3e258?p=2096 (存取密碼: 2096)