ABP 应用服务源码解读:ApplicationService 基类内置了哪些能力

ApplicationService 的声明

// framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/ApplicationService.cs
public abstract class ApplicationService :
    IApplicationService,
    IAvoidDuplicateCrossCuttingConcerns,
    IValidationEnabled,           // ← 自动验证
    IUnitOfWorkEnabled,           // ← 自动事务
    IAuditingEnabled,             // ← 自动审计
    IGlobalFeatureCheckingEnabled, // ← 自动特性检查
    ITransientDependency          // ← 自动注册

继承 ApplicationService 的类自动获得 5 个横切关注点。

横切关注点的拦截实现

这些接口不是装饰器,而是被 Castle DynamicProxy(AOP 框架)拦截的。ABP 为每个实现了这些标记接口的类创建代理,在方法调用前后插入横切逻辑。

// 以验证为例,执行顺序:
1. UnitOfWorkInterceptor    → 开启事务
2. AuditingInterceptor      → 记录审计日志
3. AuthorizeInterceptor     → 检查权限
4. ValidationInterceptor    → 验证参数
5. → 执行业务方法 ←
6. UnitOfWorkInterceptor    → 提交事务

内置的快捷属性

// 以下属性可以直接使用,不需要手动注入
public abstract class ApplicationService
{
    protected IGuidGenerator GuidGenerator { get; }      // ID 生成
    protected ICurrentUser CurrentUser { get; }           // 当前用户
    protected ICurrentTenant CurrentTenant { get; }       // 当前租户
    protected IObjectMapper ObjectMapper { get; }         // 对象映射
    protected IUnitOfWorkManager UnitOfWorkManager { get; } // 事务管理
    protected IAuthorizationService AuthorizationService { get; } // 授权
    protected IClock Clock { get; }                       // 时间
    protected IStringLocalizer L { get; }                 // 本地化
    protected ILogger Logger { get; }                     // 日志
    protected ISettingProvider SettingProvider { get; }   // 设置
    protected IFeatureChecker FeatureChecker { get; }     // 特性开关
    protected IDataFilter DataFilter { get; }             // 数据过滤
    protected IAsyncQueryableExecuter AsyncExecuter { get; } // 异步查询
}

这些属性都是通过 LazyServiceProvider 延迟加载的,只有在使用时才从 DI 容器解析,不会增加构造开销。

CrudAppService 源码解读

CrudAppService 位于 framework/src/Volo.Abp.Ddd.Application/Volo/Abp/Application/Services/CrudAppService.cs,它把 CRUD 操作模板化了。

GetAsync 为例:

// 抽象基类中的实现
protected override async Task<TEntity> GetEntityByIdAsync(TKey id)
{
    return await Repository.GetAsync(id);  // 委托给仓储
}

// 然后由 CrudAppService 的 MapToGetOutputDtoAsync 映射为 DTO
protected override Task<TGetOutputDto> MapToGetOutputDtoAsync(TEntity entity)
{
    return Task.FromResult(ObjectMapper.Map<TEntity, TGetOutputDto>(entity));
}

CrudAppService 暴露了多个 virtual 方法,开发者可以按需覆写:

public class BookAppService : CrudAppService<Book, BookDto, Guid>
{
    // 覆写创建时的额外逻辑
    protected override async Task<Book> MapToEntityAsync(CreateBookDto createInput)
    {
        var book = await base.MapToEntityAsync(createInput);
        book.Status = BookStatus.Draft;  // 设置默认值
        return book;
    }

    // 覆写查询过滤
    protected override async Task<IQueryable<Book>> CreateFilteredQueryAsync(PagedAndSortedResultRequestDto input)
    {
        return (await Repository.GetQueryableAsync())
            .Where(b => !b.IsHidden);  // 过滤掉隐藏的
    }
}

实践:应用服务的设计原则

// 推荐:每个方法只做一件事,使用 CrudAppService 减少模板代码
public class BookAppService :
    CrudAppService<Book, BookDto, Guid, BookListDto, CreateBookDto, UpdateBookDto>
{
    public BookAppService(IRepository<Book, Guid> repo) : base(repo) { }
}

// 复杂业务:使用 ApplicationService 基类提供的快捷属性
public class OrderAppService : ApplicationService, IOrderAppService
{
    public async Task<OrderDto> CreateAsync(CreateOrderDto input)
    {
        var order = ObjectMapper.Map<CreateOrderDto, Order>(input);
        order.Id = GuidGenerator.Create();
        order.TenantId = CurrentTenant.Id;

        Logger.LogInformation("用户 {UserId} 创建订单 {OrderId}", CurrentUser.Id, order.Id);

        await Repository.InsertAsync(order);
        return ObjectMapper.Map<Order, OrderDto>(order);
    }
}
posted @ 2026-08-05 10:36  DLForge  阅读(54)  评论(0)    收藏  举报