欢迎光临
我们一直在努力

3.2 ABP Business版 10.0实战指南:应用服务开发与业务逻辑构建

3.2 应用服务开发

3.2.1 应用服务基础概念

应用服务是连接领域层和表示层的桥梁,负责处理业务逻辑、数据转换和事务管理。在ABP框架中,应用服务通常用于:

  • 处理来自表示层的请求
  • 协调领域对象执行业务逻辑
  • 转换领域对象为DTO(数据传输对象)
  • 管理事务
  • 处理权限和异常
  • 实现业务流程

应用服务的核心原则包括:

  • 封装业务逻辑:将复杂的业务逻辑封装在应用服务中
  • 数据转换:负责领域对象和DTO之间的转换
  • 事务管理:确保业务操作的原子性
  • 权限控制:验证用户是否有权执行特定操作
  • 异常处理:处理业务异常并返回友好的错误信息

3.2.2 ABP框架中的应用服务基类

ABP框架提供了一系列应用服务基类,简化了应用服务的创建和管理:

基类描述适用场景
ApplicationService 基本应用服务基类,提供常用的应用服务功能 所有应用服务
CrudAppService<TEntity, TDto, TKey> 提供CRUD操作的应用服务基类 需要基本CRUD功能的应用服务
AsyncCrudAppService<TEntity, TDto, TKey> 异步CRUD应用服务基类 需要异步CRUD功能的应用服务
CrudAppService<TEntity, TDto, TKey, TGetListInput, TCreateInput, TUpdateInput> 完整的CRUD应用服务基类 需要完整CRUD功能的应用服务

3.2.3 应用服务接口定义

应用服务接口定义了应用服务提供的功能,是表示层与应用服务层的契约。

3.2.3.1 基本应用服务接口

创建一个基本的图书应用服务接口:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;

namespace BookStore.Application.Books
{
// 图书应用服务接口,继承自IApplicationService
public interface IBookAppService : IApplicationService
{
// 获取图书列表
Task<PagedResultDto<BookDto>> GetListAsync(GetBookListDto input);

// 获取单个图书
Task<BookDto> GetAsync(Guid id);

// 创建图书
Task<BookDto> CreateAsync(CreateBookDto input);

// 更新图书
Task<BookDto> UpdateAsync(Guid id, UpdateBookDto input);

// 删除图书
Task DeleteAsync(Guid id);

// 获取可用图书列表
Task<List<BookDto>> GetAvailableBooksAsync();

// 获取图书统计信息
Task<BookStatisticsDto> GetStatisticsAsync();
}
}

3.2.3.2 继承自ICrudAppService的接口

如果应用服务只需要基本的CRUD功能,可以继承自ICrudAppService接口:

using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;

namespace BookStore.Application.Authors
{
// 作者应用服务接口,继承自ICrudAppService
public interface IAuthorAppService : ICrudAppService<
AuthorDto, // 返回的DTO类型
Guid, // 实体主键类型
PagedAndSortedResultRequestDto, // 获取列表的输入DTO类型
CreateAuthorDto, // 创建的输入DTO类型
UpdateAuthorDto // 更新的输入DTO类型
>
{
// 可以添加额外的方法
Task<List<AuthorLookupDto>> GetAuthorLookupAsync();
}
}

3.2.4 DTO设计与映射

DTO(数据传输对象)用于在应用服务层和表示层之间传输数据,避免直接暴露领域对象。

3.2.4.1 DTO设计原则
  • 扁平结构:DTO应该是扁平的,避免嵌套结构,便于表示层处理
  • 仅包含必要数据:DTO只包含表示层需要的数据,不包含内部实现细节
  • 使用值类型:DTO使用值类型,不包含引用类型,避免循环引用
  • 使用数据注解:DTO使用数据注解进行验证和格式化
  • 区分不同用途:为不同的操作(如创建、更新、查询)使用不同的DTO
  • 3.2.4.2 基本DTO示例

    创建图书相关的DTO:

    using System;
    using System.ComponentModel.DataAnnotations;
    using Volo.Abp.Application.Dtos;

    namespace BookStore.Application.Books
    {
    // 图书DTO,用于返回图书信息
    public class BookDto : FullAuditedEntityDto<Guid>
    {
    public string Name { get; set; }
    public string Isbn { get; set; }
    public decimal Price { get; set; }
    public Guid AuthorId { get; set; }
    public string AuthorName { get; set; }
    public bool IsBorrowed { get; set; }
    }

    // 获取图书列表的输入DTO
    public class GetBookListDto : PagedAndSortedResultRequestDto
    {
    public string Filter { get; set; }
    public Guid? AuthorId { get; set; }
    public bool? IsBorrowed { get; set; }
    }

    // 创建图书的输入DTO
    public class CreateBookDto
    {
    [Required]
    [StringLength(100)]
    public string Name { get; set; }

    [Required]
    [StringLength(20)]
    public string Isbn { get; set; }

    [Required]
    [Range(0.01, double.MaxValue)]
    public decimal Price { get; set; }

    [Required]
    public Guid AuthorId { get; set; }
    }

    // 更新图书的输入DTO
    public class UpdateBookDto
    {
    [Required]
    [StringLength(100)]
    public string Name { get; set; }

    [Required]
    [StringLength(20)]
    public string Isbn { get; set; }

    [Required]
    [Range(0.01, double.MaxValue)]
    public decimal Price { get; set; }

    [Required]
    public Guid AuthorId { get; set; }
    }

    // 图书统计DTO
    public class BookStatisticsDto
    {
    public int TotalBooks { get; set; }
    public int AvailableBooks { get; set; }
    public int BorrowedBooks { get; set; }
    public decimal TotalValue { get; set; }
    }

    // 图书查找DTO,用于下拉选择
    public class BookLookupDto : EntityDto<Guid>
    {
    public string Name { get; set; }
    public string Isbn { get; set; }
    }
    }

    3.2.4.3 使用AutoMapper进行映射

    ABP框架集成了AutoMapper,用于自动映射领域对象和DTO。

  • 配置AutoMapper映射:
  • using AutoMapper;
    using BookStore.Domain.Books;
    using BookStore.Domain.Authors;

    namespace BookStore.Application.Books
    {
    // 图书映射配置
    public class BookMapperProfile : Profile
    {
    public BookMapperProfile()
    {
    // 映射图书实体到图书DTO
    CreateMap<Book, BookDto>()
    .ForMember(dest => dest.AuthorName, opt => opt.MapFrom(src => src.Author.Name));

    // 映射创建DTO到图书实体
    CreateMap<CreateBookDto, Book>();

    // 映射更新DTO到图书实体
    CreateMap<UpdateBookDto, Book>();

    // 映射图书实体到图书查找DTO
    CreateMap<Book, BookLookupDto>();

    // 映射作者实体到作者查找DTO
    CreateMap<Author, AuthorLookupDto>();
    }
    }
    }

  • 注册AutoMapper配置:
  • 在模块中注册AutoMapper配置:

    using Volo.Abp.AutoMapper;
    using Volo.Abp.Modularity;

    namespace BookStore.Application
    {
    [DependsOn(
    typeof(AbpAutoMapperModule),
    typeof(BookStoreDomainModule)
    )
    ]
    public class BookStoreApplicationModule : AbpModule
    {
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
    // 配置AutoMapper
    Configure<AbpAutoMapperOptions>(options =>
    {
    options.AddMaps<BookStoreApplicationModule>();
    });

    // 其他配置…
    }
    }
    }

    3.2.5 业务逻辑实现

    应用服务的核心是实现业务逻辑,包括数据处理、事务管理和权限控制。

    3.2.5.1 基本应用服务实现

    实现图书应用服务:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Volo.Abp.Application.Dtos;
    using Volo.Abp.Application.Services;
    using Volo.Abp.Domain.Repositories;
    using BookStore.Domain.Books;
    using BookStore.Domain.Authors;

    namespace BookStore.Application.Books
    {
    // 图书应用服务实现
    public class BookAppService : ApplicationService, IBookAppService
    {
    // 注入仓储和领域服务
    private readonly IBookRepository _bookRepository;
    private readonly IAuthorRepository _authorRepository;
    private readonly BookManager _bookManager;

    public BookAppService(
    IBookRepository bookRepository,
    IAuthorRepository authorRepository,
    BookManager bookManager)
    {
    _bookRepository = bookRepository;
    _authorRepository = authorRepository;
    _bookManager = bookManager;
    }

    // 获取图书列表
    public async Task<PagedResultDto<BookDto>> GetListAsync(GetBookListDto input)
    {
    // 构建查询
    var queryable = await _bookRepository.GetQueryableAsync();

    // 应用过滤条件
    if (!string.IsNullOrWhiteSpace(input.Filter))
    {
    queryable = queryable.Where(b =>
    b.Name.Contains(input.Filter) ||
    b.Isbn.Contains(input.Filter) ||
    b.Author.Name.Contains(input.Filter));
    }

    if (input.AuthorId.HasValue)
    {
    queryable = queryable.Where(b => b.AuthorId == input.AuthorId.Value);
    }

    if (input.IsBorrowed.HasValue)
    {
    queryable = queryable.Where(b => b.IsBorrowed == input.IsBorrowed.Value);
    }

    // 应用排序
    if (string.IsNullOrWhiteSpace(input.Sorting))
    {
    queryable = queryable.OrderBy(b => b.Name);
    }
    else
    {
    queryable = queryable.OrderBy(input.Sorting);
    }

    // 执行分页查询
    var totalCount = await AsyncExecuter.CountAsync(queryable);
    var items = await AsyncExecuter.ToListAsync(queryable
    .Skip(input.SkipCount)
    .Take(input.MaxResultCount));

    // 映射到DTO并返回
    return new PagedResultDto<BookDto>(
    totalCount,
    ObjectMapper.Map<List<Book>, List<BookDto>>(items)
    );
    }

    // 获取单个图书
    public async Task<BookDto> GetAsync(Guid id)
    {
    var book = await _bookRepository.GetAsync(id);
    return ObjectMapper.Map<Book, BookDto>(book);
    }

    // 创建图书
    public async Task<BookDto> CreateAsync(CreateBookDto input)
    {
    // 使用领域服务创建图书
    var book = await _bookManager.CreateBookAsync(
    input.Name,
    input.Isbn,
    input.Price,
    input.AuthorId
    );

    // 保存到数据库
    await _bookRepository.InsertAsync(book);

    return ObjectMapper.Map<Book, BookDto>(book);
    }

    // 更新图书
    public async Task<BookDto> UpdateAsync(Guid id, UpdateBookDto input)
    {
    // 获取图书实体
    var book = await _bookRepository.GetAsync(id);

    // 更新图书信息
    book = await _bookManager.UpdateBookAsync(
    book,
    input.Name,
    input.Isbn,
    input.Price,
    input.AuthorId
    );

    // 保存到数据库
    await _bookRepository.UpdateAsync(book);

    return ObjectMapper.Map<Book, BookDto>(book);
    }

    // 删除图书
    public async Task DeleteAsync(Guid id)
    {
    await _bookRepository.DeleteAsync(id);
    }

    // 获取可用图书列表
    public async Task<List<BookDto>> GetAvailableBooksAsync()
    {
    var books = await _bookRepository.GetListAsync(b => !b.IsBorrowed);
    return ObjectMapper.Map<List<Book>, List<BookDto>>(books);
    }

    // 获取图书统计信息
    public async Task<BookStatisticsDto> GetStatisticsAsync()
    {
    var books = await _bookRepository.GetListAsync();

    return new BookStatisticsDto
    {
    TotalBooks = books.Count,
    AvailableBooks = books.Count(b => !b.IsBorrowed),
    BorrowedBooks = books.Count(b => b.IsBorrowed),
    TotalValue = books.Sum(b => b.Price)
    };
    }
    }
    }

    3.2.5.2 继承自CrudAppService的实现

    如果应用服务只需要基本的CRUD功能,可以继承自CrudAppService类:

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Volo.Abp.Application.Dtos;
    using Volo.Abp.Application.Services;
    using Volo.Abp.Domain.Repositories;
    using BookStore.Domain.Authors;

    namespace BookStore.Application.Authors
    {
    // 作者应用服务实现,继承自CrudAppService
    public class AuthorAppService : CrudAppService<
    Author, // 作者实体类型
    AuthorDto, // 返回的DTO类型
    Guid, // 实体主键类型
    PagedAndSortedResultRequestDto, // 获取列表的输入DTO类型
    CreateAuthorDto, // 创建的输入DTO类型
    UpdateAuthorDto // 更新的输入DTO类型
    >, IAuthorAppService
    {
    public AuthorAppService(IRepository<Author, Guid> repository)
    : base(repository)
    {
    }

    // 实现额外的方法
    public async Task<List<AuthorLookupDto>> GetAuthorLookupAsync()
    {
    var authors = await Repository.GetListAsync();
    return ObjectMapper.Map<List<Author>, List<AuthorLookupDto>>(authors);
    }

    // 可以重写基类的方法,添加自定义逻辑
    protected override async Task<Author> CreateAsync(CreateAuthorDto input)
    {
    // 添加自定义创建逻辑
    var author = await base.CreateAsync(input);

    // 记录创建日志
    Logger.LogInformation("Author created: {AuthorName}", author.Name);

    return author;
    }
    }
    }

    3.2.6 事务管理

    ABP框架提供了自动事务管理,确保应用服务方法在一个事务中执行。

    3.2.6.1 自动事务管理

    默认情况下,ABP框架会为所有应用服务方法自动创建事务。如果方法成功执行,事务会自动提交;如果发生异常,事务会自动回滚。

    public async Task<BookDto> CreateAsync(CreateBookDto input)
    {
    // 自动创建事务
    var book = await _bookManager.CreateBookAsync(
    input.Name,
    input.Isbn,
    input.Price,
    input.AuthorId
    );

    // 保存图书
    await _bookRepository.InsertAsync(book);

    // 创建图书创建事件
    await EventBus.PublishAsync(new BookCreatedEvent(book));

    // 如果所有操作成功,事务自动提交;如果发生异常,事务自动回滚
    return ObjectMapper.Map<Book, BookDto>(book);
    }

    3.2.6.2 手动事务管理

    如果需要手动控制事务,可以使用IUnitOfWorkManager:

    public async Task<BookDto> CreateBookWithManualTransactionAsync(CreateBookDto input)
    {
    // 获取工作单元
    using (var uow = UnitOfWorkManager.Begin())
    {
    try
    {
    var book = await _bookManager.CreateBookAsync(
    input.Name,
    input.Isbn,
    input.Price,
    input.AuthorId
    );

    await _bookRepository.InsertAsync(book);

    // 手动提交事务
    await uow.CompleteAsync();

    return ObjectMapper.Map<Book, BookDto>(book);
    }
    catch (Exception ex)
    {
    // 手动回滚事务(可选,发生异常时会自动回滚)
    await uow.RollbackAsync();
    throw;
    }
    }
    }

    3.2.6.3 事务属性配置

    可以使用UnitOfWork特性配置事务的行为:

    // 配置事务隔离级别和传播行为
    [UnitOfWork(IsolationLevel.ReadCommitted, Propagation.Required)]
    public async Task<BookDto> CreateAsync(CreateBookDto input)
    {
    // 事务配置会应用到这个方法
    var book = await _bookManager.CreateBookAsync(
    input.Name,
    input.Isbn,
    input.Price,
    input.AuthorId
    );

    await _bookRepository.InsertAsync(book);

    return ObjectMapper.Map<Book, BookDto>(book);
    }

    // 禁用事务
    [UnitOfWork(IsDisabled = true)]
    public async Task<List<BookDto>> GetAvailableBooksAsync()
    {
    // 这个方法不会在事务中执行
    var books = await _bookRepository.GetListAsync(b => !b.IsBorrowed);
    return ObjectMapper.Map<List<Book>, List<BookDto>>(books);
    }

    3.2.7 企业级最佳实践

    3.2.7.1 应用服务设计最佳实践
  • 使用应用服务接口:始终定义应用服务接口,便于测试和替换实现
  • 保持应用服务简洁:应用服务应该协调领域对象,而不是包含复杂的业务逻辑
  • 使用领域服务:将复杂的业务逻辑封装在领域服务中,应用服务调用领域服务
  • 使用DTO:始终使用DTO传输数据,避免直接暴露领域对象
  • 使用AutoMapper:使用AutoMapper自动映射领域对象和DTO,减少手动映射代码
  • 实现权限控制:在应用服务层实现权限控制,确保只有授权用户可以执行操作
  • 处理异常:优雅地处理业务异常,并返回友好的错误信息
  • 记录日志:记录应用服务的关键操作,便于调试和审计
  • 3.2.7.2 DTO设计最佳实践
  • 为不同操作使用不同DTO:为创建、更新、查询等不同操作使用不同的DTO
  • 使用数据注解:使用数据注解进行验证和格式化
  • 保持DTO扁平:DTO应该是扁平的,避免嵌套结构
  • 仅包含必要数据:DTO只包含表示层需要的数据,不包含内部实现细节
  • 使用有意义的名称:DTO和属性名称应该具有明确的业务含义
  • 实现IValidatableObject:对于复杂的验证逻辑,实现IValidatableObject接口
  • 3.2.7.3 事务管理最佳实践
  • 使用自动事务:优先使用ABP框架的自动事务管理,减少手动事务代码
  • 保持事务短小:事务应该尽量短小,避免长时间持有锁
  • 使用合适的隔离级别:根据业务需求选择合适的事务隔离级别
  • 避免在事务中执行远程调用:远程调用可能导致事务长时间持有锁
  • 使用异步操作:使用异步操作提高系统的并发性能
  • 3.2.7.4 性能优化最佳实践
  • 使用异步方法:所有I/O操作都应该使用异步方法
  • 实现分页查询:对于大量数据,使用分页查询减少内存消耗
  • 使用延迟加载:只加载必要的数据,避免加载不必要的关联数据
  • 使用缓存:对于频繁访问的数据,使用缓存提高性能
  • 优化查询:使用索引和优化的查询语句,提高查询性能
  • 3.2.8 实际案例:图书管理系统中的应用服务实现

    3.2.8.1 借阅管理应用服务

    实现图书借阅管理的应用服务:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Volo.Abp.Application.Dtos;
    using Volo.Abp.Application.Services;
    using Volo.Abp.Domain.Repositories;
    using Volo.Abp.Users;
    using BookStore.Domain.Books;
    using BookStore.Domain.Borrowing;
    using BookStore.Domain.Users;

    namespace BookStore.Application.Borrowing
    {
    // 借阅管理应用服务
    public class BorrowingAppService : ApplicationService, IBorrowingAppService
    {
    private readonly IRepository<BorrowingRecord, Guid> _borrowingRecordRepository;
    private readonly IRepository<Book, Guid> _bookRepository;
    private readonly ICurrentUser _currentUser;
    private readonly BorrowingManager _borrowingManager;

    public BorrowingAppService(
    IRepository<BorrowingRecord, Guid> borrowingRecordRepository,
    IRepository<Book, Guid> bookRepository,
    ICurrentUser currentUser,
    BorrowingManager borrowingManager)
    {
    _borrowingRecordRepository = borrowingRecordRepository;
    _bookRepository = bookRepository;
    _currentUser = currentUser;
    _borrowingManager = borrowingManager;
    }

    // 借阅图书
    public async Task<BorrowingRecordDto> BorrowBookAsync(BorrowBookDto input)
    {
    // 获取当前用户ID
    var userId = _currentUser.GetId();

    // 使用领域服务处理借阅逻辑
    var borrowingRecord = await _borrowingManager.BorrowBookAsync(
    input.BookId,
    userId,
    input.Remarks
    );

    // 保存借阅记录
    await _borrowingRecordRepository.InsertAsync(borrowingRecord);

    return ObjectMapper.Map<BorrowingRecord, BorrowingRecordDto>(borrowingRecord);
    }

    // 归还图书
    public async Task<BorrowingRecordDto> ReturnBookAsync(Guid id)
    {
    // 获取借阅记录
    var borrowingRecord = await _borrowingRecordRepository.GetAsync(id);

    // 使用领域服务处理归还逻辑
    await _borrowingManager.ReturnBookAsync(borrowingRecord);

    // 更新借阅记录
    await _borrowingRecordRepository.UpdateAsync(borrowingRecord);

    return ObjectMapper.Map<BorrowingRecord, BorrowingRecordDto>(borrowingRecord);
    }

    // 获取用户借阅记录
    public async Task<PagedResultDto<BorrowingRecordDto>> GetUserBorrowingRecordsAsync(GetBorrowingRecordsDto input)
    {
    var userId = _currentUser.GetId();

    // 构建查询
    var queryable = await _borrowingRecordRepository.GetQueryableAsync();

    // 过滤当前用户的借阅记录
    queryable = queryable.Where(br => br.UserId == userId);

    // 应用其他过滤条件
    if (input.BookId.HasValue)
    {
    queryable = queryable.Where(br => br.BookId == input.BookId.Value);
    }

    if (input.IsReturned.HasValue)
    {
    queryable = input.IsReturned.Value
    ?
    queryable.Where(br => br.ReturnDate.HasValue)
    : queryable.Where(br => !br.ReturnDate.HasValue);
    }

    // 应用排序
    if (string.IsNullOrWhiteSpace(input.Sorting))
    {
    queryable = queryable.OrderByDescending(br => br.BorrowDate);
    }
    else
    {
    queryable = queryable.OrderBy(input.Sorting);
    }

    // 执行分页查询
    var totalCount = await AsyncExecuter.CountAsync(queryable);
    var items = await AsyncExecuter.ToListAsync(queryable
    .Skip(input.SkipCount)
    .Take(input.MaxResultCount));

    return new PagedResultDto<BorrowingRecordDto>(
    totalCount,
    ObjectMapper.Map<List<BorrowingRecord>, List<BorrowingRecordDto>>(items)
    );
    }

    // 获取所有借阅记录(管理员使用)
    [Authorize(BorrowingPermissions.BorrowingRecords.ViewAll)]
    public async Task<PagedResultDto<BorrowingRecordDto>> GetAllBorrowingRecordsAsync(GetBorrowingRecordsDto input)
    {
    // 构建查询
    var queryable = await _borrowingRecordRepository.GetQueryableAsync();

    // 应用过滤条件
    if (input.BookId.HasValue)
    {
    queryable = queryable.Where(br => br.BookId == input.BookId.Value);
    }

    if (input.UserId.HasValue)
    {
    queryable = queryable.Where(br => br.UserId == input.UserId.Value);
    }

    if (input.IsReturned.HasValue)
    {
    queryable = input.IsReturned.Value
    ?
    queryable.Where(br => br.ReturnDate.HasValue)
    : queryable.Where(br => !br.ReturnDate.HasValue);
    }

    // 应用排序
    if (string.IsNullOrWhiteSpace(input.Sorting))
    {
    queryable = queryable.OrderByDescending(br => br.BorrowDate);
    }
    else
    {
    queryable = queryable.OrderBy(input.Sorting);
    }

    // 执行分页查询
    var totalCount = await AsyncExecuter.CountAsync(queryable);
    var items = await AsyncExecuter.ToListAsync(queryable
    .Skip(input.SkipCount)
    .Take(input.MaxResultCount));

    return new PagedResultDto<BorrowingRecordDto>(
    totalCount,
    ObjectMapper.Map<List<BorrowingRecord>, List<BorrowingRecordDto>>(items)
    );
    }
    }
    }

    3.2.8.2 应用服务权限控制

    在应用服务中实现权限控制:

    using Volo.Abp.Application.Services;
    using Volo.Abp.Authorization.Permissions;
    using Volo.Abp.Domain.Repositories;
    using BookStore.Domain.Books;

    namespace BookStore.Application.Books
    {
    public class BookAppService : ApplicationService, IBookAppService
    {
    private readonly IPermissionChecker _permissionChecker;
    private readonly IBookRepository _bookRepository;

    public BookAppService(
    IPermissionChecker permissionChecker,
    IBookRepository bookRepository)
    {
    _permissionChecker = permissionChecker;
    _bookRepository = bookRepository;
    }

    public async Task DeleteAsync(Guid id)
    {
    // 检查删除权限
    if (!await _permissionChecker.IsGrantedAsync(BookStorePermissions.Books.Delete))
    {
    throw new AbpAuthorizationException("You don't have permission to delete books.");
    }

    await _bookRepository.DeleteAsync(id);
    }

    // 使用特性实现权限控制
    [Authorize(BookStorePermissions.Books.Create)]
    public async Task<BookDto> CreateAsync(CreateBookDto input)
    {
    // 权限检查由特性自动处理
    // …
    }
    }
    }

    3.2.9 实践练习

  • 创建应用服务接口:创建图书管理系统的应用服务接口,包括图书、作者、借阅记录等
  • 设计DTO:设计各种DTO,包括创建、更新、查询等不同用途的DTO
  • 配置AutoMapper:配置领域对象和DTO之间的映射
  • 实现应用服务:实现应用服务的业务逻辑,包括CRUD操作和自定义方法
  • 添加事务管理:确保应用服务方法在事务中执行
  • 实现权限控制:在应用服务中添加权限检查
  • 优化性能:使用异步方法、分页查询等优化性能
  • 3.2.10 总结与进阶指南

    3.2.10.1 本章总结
    • 应用服务是连接领域层和表示层的桥梁,负责处理业务逻辑、数据转换和事务管理
    • ABP框架提供了一系列应用服务基类,简化了应用服务的创建和管理
    • 应用服务接口定义了应用服务提供的功能,是表示层与应用服务层的契约
    • DTO用于在应用服务层和表示层之间传输数据,避免直接暴露领域对象
    • ABP框架集成了AutoMapper,用于自动映射领域对象和DTO
    • 应用服务方法默认在事务中执行,确保业务操作的原子性
    • 应用服务层应该实现权限控制,确保只有授权用户可以执行操作
    3.2.10.2 进阶学习资源
  • ABP框架应用服务文档
  • AutoMapper官方文档
  • 领域驱动设计:软件核心复杂性应对之道
  • 事务管理最佳实践
  • 异步编程最佳实践
  • 通过本章的学习,你已经掌握了ABP框架中应用服务开发的核心概念和最佳实践。在实际开发中,合理设计和实现应用服务可以大大提高系统的可维护性、可扩展性和性能。

    下一章,我们将学习MVC控制器与视图开发,了解如何实现表示层的功能。

    赞(0)
    未经允许不得转载:171主机测评 » 3.2 ABP Business版 10.0实战指南:应用服务开发与业务逻辑构建
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址