乐趣区

关于程序员:基于ABP实现DDD领域逻辑和应用逻辑

  本文次要介绍了多应用层的问题,包含起因和实现。通过了解介绍了如何辨别畛域逻辑和应用逻辑,哪些是正确的实际,哪些是不举荐的或者谬误的实际。

一. 多应用层的问题

1. 多应用层介绍

  不晓得你们是否会遇到一种状况,通过 ABP 构建了一个后端的 API 我的项目,刚开始是为 Web 端我的项目 (比方,Vue) 提供后端接口服务的,随着我的项目的倒退和业务的简单,减少了挪动端的 App,或者公众号、小程序等,这样不仅要为 Web 端提供 API 服务,而且还须要为挪动端的 App,或者公众号、小程序等提供 API 服务。这个场景就是多应用层的问题。也就是说你当初须要构建一个有多个应用程序的零碎了:

  • Web 应用程序:比方应用的 ASP.NET Core MVC 技术,次要用来给用户展现产品,游客模式是能够查看产品的,并不需要登录和验证。
  • 后端管理应用程序:比方前端是 Vue,后端的 ASP.NET Core API,次要用来对产品进行增删改等操作。
  • 挪动应用程序:比方前端是 uni-app,后端是 ASP.NET Core API,通过 REST 接口和后端通信。

    2. 多应用层例子

      因为业务的复杂性,每个利用零碎都有本人的不同应用服务办法,不同的输出和输入 DTO,不必的认证和受权规定等,所以如果把所有的业务逻辑都融入到一个利用零碎中,就会让零碎更难开发、保护和测试,并导致潜在的 Bug 危险。因而,为每个应用程序创立独自的应用层,并且它们都是用单个畛域层来共享外围畛域逻辑。为了更加具体的阐明,为每种应用程序类型创立不同的.csproj 我的项目:

  • 后端管理应用程序:IssueTracker.Admin.Application 和 IssueTracker.Admin.Application.Contracts 我的项目
  • Web 应用程序:IssueTracker.Public.Application 和 IssueTracker.Public.Application.Contracts 我的项目
  • 挪动应用程序:IssueTracker.Mobile.Application 和 IssueTracker.Mobile.Application.Contracts 我的项目

二. 如何辨别畛域逻辑和应用逻辑

通常,DDD 中的业务逻辑包含畛域逻辑和应用逻辑。畛域逻辑由零碎的外围畛域规定组成,而利用程序逻辑实现特定于应用程序的用例。话虽这样说,然而并不容易辨别什么是畛域逻辑和应用逻辑。

1. 在畛域服务层中创立组织 Organization

上面通过在畛域服务中创立 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("systemadmin@issuetracking.com", "新组织", "新组织名称:"+name);
        
        // 返回一个组织实例
        return organization;
    }
}
  • 畛域服务不做权限验证,权限验证放在应用层来做
  • 用户概念是应用层或展现层的相干概念,记录日志不应该蕴含以后用户的用户名
  • 创立一个新的组织,并发送邮件,这个业务逻辑也应该放在应用层

2. 在应用层中应用畛域服务创立组织 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("systemadmin@issuetracking.com", "新组织", "新组织名称:"+name);
        
        // 返回实例[谬误]
        return organization;
    }
    private double GetOrganizationPrice()
    {return 42;//Gets form somewhere...}
}

应用服务层的输出和输入参数都是 DTO,不能返回实体。至于为什么不将领取放在畛域服务中,只能说业务重要也不肯定放在畛域服务中,具体起因阐明参考[1]。

参考文献:
[1]基于 ABP Framework 实现畛域驱动设计:https://url39.ctfile.com/f/25… (拜访明码: 2096)

本文由 mdnice 多平台公布

退出移动版