在系列教程中,我们会构建一个基于ABP的Web应用程序,用于管理书籍及其作者列表
使用到的技术:
Entity Framework Core
Angular
本教程分为以下部分:
前言 在前面的部分中,我们使用了ABP基础设施来快速创建了一些服务:
使用 CrudAppService 基类,而不是手动开发用于标准创建、读取、更新和删除操作的应用程序服务。
使用通用存储库完全自动化数据库层。
那么,对于后面的Author
部分
手动创建领域服务和应用服务接口,以了解如何手动实现。
实现领域驱动设计(DDD)最佳实践。
开发将逐层完成,以一次性专注于单个层。在实际项目中,可以像前面部分一样按功能(垂直)开发应用程序功能。
Entity 在 Acme.BookStore.Domain
项目中创建一个 Authors
文件夹(命名空间),并新建一个 Author
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 using System;using Volo.Abp;using Volo.Abp.Domain.Entities.Auditing;namespace Acme.BookStore.Authors ;public class Author : FullAuditedAggregateRoot <Guid >{ public string Name { get ; private set ; } public DateTime BirthDate { get ; set ; } public string ShortBio { get ; set ; } private Author ( ) { } internal Author ( Guid id, string name, DateTime birthDate, string ? shortBio = null ) : base (id ) { SetName(name); birthDate = BirthDate; ShortBio = shortBio; } internal Author ChangeName (string name ) { SetName(name); return this ; } private void SetName (string name ) { Name = Check.NotNullOrWhiteSpace( name, nameof (name), maxLength: AuthorConsts.MaxNameLength ); } }
继承自 FullAuditedAggregateRoot<Guid>
,使用soft delete,并记录所有审计信息
Name - private set
,限制从类中设置此属性,有两种方法可以设置名称:
两种方法都会校验名称
ChangeName方法设置为internal
, 强制仅在领域层使用方法
Check
类为ABP帮助类,可以检查方法参数
在.Domain.Shared
项目中创建AuthorConsts类:
1 2 3 4 5 6 namespace Acme.BookStore.Authors ;public class AuthorConsts { public const int MaxNameLength = 64 ; }
Repository 在 Acme.BookStore.Domain
项目的 Authors
文件夹(命名空间)中创建IAuthorRepository
接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 using System.Collections.Generic;using System.Threading.Tasks;using System;using Volo.Abp.Domain.Repositories;namespace Acme.BookStore.Authors ;public interface IAuthorRepository : IRepository <Author , Guid >{ Task<Author> FindByNameAsync (string name ) ; Task<List<Author>> GetListAsync( int skipCount, int maxResultCount, string sorting, string filter = null ); }
IAuthorRepository
扩展了标准 IRepository<Author, Guid>
接口,因此所有标准存储库方法也可用于 IAuthorRepository
。
FindByNameAsync
用于 AuthorManager
按姓名查询作者。
GetListAsync
将在应用程序层中用于获取要在 UI 上显示的列出、排序和筛选的作者列表。
Domain 在 Acme.BookStore.Domain
项目的 Authors
文件夹(命名空间)中创建一个 AuthorManager
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 using System.Threading.Tasks;using System;using Volo.Abp;using Volo.Abp.Domain.Services;namespace Acme.BookStore.Authors ;public class AuthorManager : DomainService { private readonly IAuthorRepository _authorRepository; public AuthorManager (IAuthorRepository authorRepository ) { _authorRepository = authorRepository; } public async Task<Author> CreateAsync ( string name, DateTime birthDate, string ? shortBio = null ) { Check.NotNullOrWhiteSpace(name, nameof (name)); var existingAuthor = await _authorRepository.FindByNameAsync(name); if (existingAuthor != null ) { throw new AuthorAlreadyExistsException(name); } return new Author( GuidGenerator.Create(), name, birthDate, shortBio ); } public async Task ChangeNameAsync ( Author author, string newName ) { Check.NotNull(author, nameof (author)); Check.NotNullOrWhiteSpace(newName, nameof (newName)); var existingAuthor = await _authorRepository.FindByNameAsync(newName); if (existingAuthor != null && existingAuthor.Id != author.Id) { throw new AuthorAlreadyExistsException(newName); } author.ChangeName(newName); } }
DDD 提示:除非确实需要领域服务方法并执行一些核心业务规则,否则不要引入领域服务方法
这两种方法都会检查是否已经存在具有给定名称的作者,并抛出在 Acme.BookStore.Domain
项目( Authors
文件夹中)中定义的特殊业务异常, AuthorAlreadyExistsException
如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 using Volo.Abp;namespace Acme.BookStore.Authors ;public class AuthorAlreadyExistsException : BusinessException { public AuthorAlreadyExistsException (string name ) : base (BookStoreDomainErrorCodes.AuthorAlreadyExists ) { WithData("name" , name); } }
BusinessException
是一种特殊的异常类型。在需要时抛出与领域层相关的异常。它由ABP框架自动处理,方便本地化。WithData(...)
方法用于向异常对象提供其他数据,将用于本地化消息或用于某些其他操作。
在 Acme.BookStore.Domain.Shared
项目中打开并 BookStoreDomainErrorCodes
更改,如下所示:
1 2 3 4 5 6 7 namespace Acme.BookStore ;public static class BookStoreDomainErrorCodes { public const string AuthorAlreadyExists = "BookStore:00001" ; }
打开 Acme.BookStore.Domain.Shared
项目 Localization/BookStore/en.json
并添加以下配置:
1 "BookStore:00001" : "There is already an author with the same name: {name}"
抛出 AuthorAlreadyExistsException
时,用户会在 UI 上看到此错误消息。
目录 这部分涵盖了书店应用程序的作者功能的领域层。下图展示了此部分中创建/更新的主要文件:
下一节 教程下一节