ApplicationService 的声明
csharp
// 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 为每个实现了这些标记接口的类创建代理,在方法调用前后插入横切逻辑。
csharp
// 以验证为例,执行顺序:
1. UnitOfWorkInterceptor → 开启事务
2. AuditingInterceptor → 记录审计日志
3. AuthorizeInterceptor → 检查权限
4. ValidationInterceptor → 验证参数
5. → 执行业务方法 ←
6. UnitOfWorkInterceptor → 提交事务
内置的快捷属性
csharp
// 以下属性可以直接使用,不需要手动注入
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 为例:
csharp
// 抽象基类中的实现
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 方法,开发者可以按需覆写:
csharp
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); // 过滤掉隐藏的
}
}
实践:应用服务的设计原则
csharp
// 推荐:每个方法只做一件事,使用 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);
}
}