Scopes & Advanced DI — Series 2

Preview — 3 of 10 questions

Which instances are the same object?

javascript
const a = await this.moduleRef.resolve(TransientService);
const b = await this.moduleRef.resolve(TransientService);
const contextId = ContextIdFactory.create();
const c = await this.moduleRef.resolve(TransientService, contextId);
const d = await this.moduleRef.resolve(TransientService, contextId);
AAll four — resolve() always returns the module's cached singleton
BOnly c and d — each bare resolve() call creates its own DI sub-tree, while passing the same contextId twice reuses the instance created for that context
COnly a and b — instances without an explicit context share a default context, and each explicit contextId produces a fresh one
DNone — resolve() creates a new instance on every call regardless of the arguments

What is the consequence of this wiring?

javascript
@Injectable({ scope: Scope.REQUEST })
export class TenantContext { constructor(@Inject(REQUEST) readonly req: Request) {} }

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private readonly tenant: TenantContext) {}
}

@Module({ providers: [{ provide: APP_GUARD, useClass: RolesGuard }] })
export class AppModule {}
ARolesGuard is promoted to request scope by bubbling, so a new guard (and a new TenantContext) is instantiated for every incoming request — correct, but measurably more expensive than a singleton guard
BThe guard stays a singleton and receives the TenantContext belonging to whichever request happened to arrive first
CNest rejects the configuration at startup, because APP_* enhancers must be default-scoped
DThe guard is instantiated once per route rather than once per request

Why is injecting AuditService into NightlyJob problematic?

javascript
@Injectable({ scope: Scope.REQUEST })
export class AuditService {
  constructor(@Inject(REQUEST) private readonly request: Request) {}
}

@Injectable()
export class NightlyJob {
  @Cron('0 3 * * *')
  async run() { /* needs AuditService */ }
}
ACron handlers may not use dependency injection at all
B@Cron methods run before the DI container is built, so no provider is available
CRequest-scoped providers are silently converted to singletons outside HTTP, giving stale data
DA scheduled job has no incoming request, so there is no request context to resolve against — the REQUEST token has nothing meaningful to provide and the scope-bubbled job cannot be instantiated as a normal singleton

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.