NestJS CQRS 中QueryHandler的Repository等依赖注入失败如何解决
NestJS CQRS 请求作用域依赖注入失败解决方案
问题现象
实现CQRS模式时,@QueryHandler修饰的类中所有注入的依赖均为undefined,执行方法时触发如下报错:
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'getCustomer' of undefined at CustomerHandler.execute
相关代码参考
1. Request作用域业务服务
@Injectable({scope: Scope.REQUEST}) export class CustomerService { constructor( @Inject(REQUEST) private readonly req: Request, private readonly queryBus: QueryBus, ) {} }
2. Query 处理器定义
@QueryHandler(CustomerQuery) export class CustomerHandler implements IQueryHandler<CustomerQuery> { constructor( private readonly repository: CustomerRepository, ) {} async execute(query: CustomerQuery) { const {response, id, name} = query; this.repository.getCustomer(response, id, name); } }
3. 模块配置
@Module({ imports: [Logger, CqrsModule], providers: [CustomerService, ...QueryHandlers, CustomerRepository], exports: [CustomerService], }) export class CustomerModule {}
4. Repository 定义(注入了REQUEST对象)
@Injectable() export class CustomerRepository { constructor( @Inject(REQUEST) private readonly req: Request, ) {} }
根因说明
CqrsModule的所有Provider均为静态作用域,底层设计不支持依赖请求作用域的Provider。如果Handler或者其依赖注入了
REQUEST这类请求作用域的对象,会导致Handler的依赖注入链路失效。该问题是Cqrs模块的已知设计限制,非代码Bug。
可行解决方案
方案1:透传请求上下文(推荐,性能损耗最低)
取消在Handler及其依赖中注入REQUEST对象,将请求上下文通过Query的payload透传:
- 修改Query定义,新增请求上下文参数
- 业务服务调用QueryBus时传入当前请求对象
this.queryBus.execute(new CustomerQuery(this.req, response, id, name))
- Handler执行时取出请求上下文,传入Repository方法
async execute(query: CustomerQuery) { const {req, response, id, name} = query; this.repository.getCustomer(req, response, id, name); }
- 调整Repository定义,移除
REQUEST注入
@Injectable() export class CustomerRepository { getCustomer(req: Request, response: any, id: string, name: string) { // 业务逻辑实现 } }
方案2:动态获取请求作用域实例
如果必须保留Repository的REQUEST注入,可以通过ModuleRef在执行阶段动态解析实例:
- Handler中注入
ModuleRef,执行时通过上下文ID解析依赖
@QueryHandler(CustomerQuery) export class CustomerHandler implements IQueryHandler<CustomerQuery> { constructor(private readonly moduleRef: ModuleRef) {} async execute(query: CustomerQuery) { const {contextId, response, id, name} = query; // 动态解析请求作用域的Repository实例 const repository = await this.moduleRef.resolve(CustomerRepository, contextId, { strict: false }); repository.getCustomer(response, id, name); } }
- 业务服务调用QueryBus时传入当前请求的上下文ID
const contextId = ContextIdFactory.getByRequest(this.req); this.queryBus.execute(new CustomerQuery(contextId, response, id, name))
内容的提问来源于stack exchange,提问作者s.k
相关产品推荐
相关产品推荐

