ModuleRef cho phép lấy provider từ IoC container lúc runtime thay vì khai báo ở constructor — dùng khi provider được chọn động (theo tên driver, theo tenant) hoặc khi code chạy ngoài luồng request thông thường.
Hai method, phân biệt rõ:
- get(Token) — chỉ lấy được provider singleton (scope DEFAULT). Thêm { strict: false } để tìm ra ngoài module hiện tại.
- resolve(Token) — dành cho provider REQUEST-scoped hoặc TRANSIENT; trả về Promise và tạo instance mới theo contextId.
@Injectable()
export class ReportJob {
constructor(private moduleRef: ModuleRef) {}
@Cron('0 2 * * *')
async run() {
const contextId = ContextIdFactory.create()
this.moduleRef.registerRequestByContextId({ tenantId: 'acme' }, contextId)
const service = await this.moduleRef.resolve(ReportService, contextId)
await service.build()
}
}Không có contextId, mỗi lần resolve() sinh một sub-tree DI mới; muốn nhiều provider dùng chung một context thì phải truyền cùng contextId. Với cron/queue, provider REQUEST-scoped không tự có REQUEST — phải registerRequestByContextId để cung cấp object đóng vai request.
Dùng có chừng mực: ModuleRef là service locator, làm phụ thuộc trở nên ẩn. Ưu tiên constructor injection, chỉ dùng ModuleRef khi thật sự cần chọn provider động.