ASP.NET Zero中调用复杂内置服务的最优实现方式咨询
我在ASP.NET Zero Boilerplate框架下实现了两个简单服务Service1与Service2,通过传入IAbpSession实例就能完成服务间调用且运行正常。但面对构造函数依赖较多的内置复杂服务(比如EditionAppService)时,没办法直接获取其构造所需参数来实例化调用。
我希望以最小改动的方式,在Service2中调用EditionAppService的GetEditions方法,目前尝试直接实例化EditionAppService但缺少构造依赖参数,请问最优实现方案是什么?
相关代码示例
简单服务示例
public class Service2: PPlusAppServiceBase { private readonly IAbpSession _session; public Service2(IAbpSession session) { _session = session; } public Entity getEntity() { Entity et = new Entity(); Service1 _service1 = new Service1(_session); [...] _service1.getEntity(); [...] return et; } } public class Service1: PPlusAppServiceBase { private readonly IAbpSession _session; public Service1(IAbpSession session) { _session = session; } public Entity getEntity() { _session.[...] return et; } }
复杂内置服务示例
public class EditionAppService : PPlusAppServiceBase, IEditionAppService { private readonly EditionManager _editionManager; private readonly IRepository<SubscribableEdition> _editionRepository; private readonly IRepository<Tenant> _tenantRepository; private readonly IBackgroundJobManager _backgroundJobManager; public EditionAppService( EditionManager editionManager, IRepository<SubscribableEdition> editionRepository, IRepository<Tenant> tenantRepository, IBackgroundJobManager backgroundJobManager) { _editionManager = editionManager; _editionRepository = editionRepository; _tenantRepository = tenantRepository; _backgroundJobManager = backgroundJobManager; } [AbpAuthorize(AppPermissions.Pages_Editions)] public async Task<ListResultDto<EditionListDto>> GetEditions() { // 方法实现代码 } }
首先得纠正一个关键问题:你手动实例化Service1的方式其实不符合ASP.NET Zero(基于Abp框架)的设计理念,Abp的核心就是依赖注入(DI),手动实例化会跳过DI容器的生命周期管理、拦截器(比如权限验证、事务处理)等关键功能,对于复杂服务这种方式更是不可行。
针对你的需求,最优方案是通过**构造函数注入IEditionAppService**来调用,完全不需要手动实例化,具体步骤如下:
1. 修改Service2的构造函数注入IEditionAppService
直接在Service2的构造函数中添加IEditionAppService的依赖,Abp的DI容器会自动帮你解决所有嵌套依赖(包括EditionManager、各种Repository等):
public class Service2: PPlusAppServiceBase { private readonly IAbpSession _session; private readonly IEditionAppService _editionAppService; // 新增依赖 // 修改构造函数注入IEditionAppService public Service2(IAbpSession session, IEditionAppService editionAppService) { _session = session; _editionAppService = editionAppService; } public async Task<Entity> getEntity() { // 注意如果调用异步方法,建议改成async方法 Entity et = new Entity(); // 直接调用EditionAppService的方法 var editions = await _editionAppService.GetEditions(); // 处理你的业务逻辑... return et; } }
2. (可选)修正Service1的调用方式
同样的,Service1也应该通过依赖注入来获取,而不是手动实例化(这是更规范的做法):
// 先给Service1定义接口,符合依赖倒置原则 public interface IService1 { Entity getEntity(); } public class Service1: PPlusAppServiceBase, IService1 { private readonly IAbpSession _session; public Service1(IAbpSession session) { _session = session; } public Entity getEntity() { // 实现逻辑 return new Entity(); } } // 然后在Service2中注入IService1 public class Service2: PPlusAppServiceBase { private readonly IAbpSession _session; private readonly IEditionAppService _editionAppService; private readonly IService1 _service1; // 新增依赖 public Service2(IAbpSession session, IEditionAppService editionAppService, IService1 service1) { _session = session; _editionAppService = editionAppService; _service1 = service1; } public async Task<Entity> getEntity() { Entity et = new Entity(); var service1Entity = _service1.getEntity(); var editions = await _editionAppService.GetEditions(); // 业务逻辑处理 return et; } }
为什么这是最优方案?
- 最小改动:只需要修改构造函数添加依赖,不需要手动处理任何复杂的依赖参数,DI容器会自动搞定。
- 符合框架设计:遵循Abp的依赖注入原则,保留框架的所有特性(比如
[AbpAuthorize]权限验证、事务、日志拦截器等)——如果手动实例化EditionAppService,[AbpAuthorize]注解会失效,因为拦截器是通过DI容器动态代理实现的。 - 可维护性高:后续如果
EditionAppService的构造函数参数变化,你不需要修改Service2的代码,DI容器会自动适配。
特殊情况:如果无法通过构造函数注入怎么办?
如果因为某些特殊原因(比如在非托管类中)无法使用构造函数注入,可以通过IocManager来解析服务:
// 在Service2中直接使用IocManager(PPlusAppServiceBase已继承IIocManagerAccessor) var editionAppService = IocManager.Resolve<IEditionAppService>(); try { var editions = await editionAppService.GetEditions(); } finally { // 记得释放手动解析的transient生命周期服务 IocManager.Release(editionAppService); }
不过这种方式是兜底方案,优先推荐构造函数注入。
内容的提问来源于stack exchange,提问作者Francisco de Javier

