Passer au contenu

Référence du module

Nest fournit la classe ModuleRef pour naviguer dans la liste interne des fournisseurs et obtenir une référence à tout fournisseur en utilisant son jeton d’injection comme clé de recherche. La classe ModuleRef fournit également un moyen d’instancier dynamiquement à la fois des fournisseurs statiques et scoped. ModuleRef peut être injecté dans une classe de la manière habituelle :

cats.service.ts
@Injectable()
export class CatsService {
constructor(private moduleRef: ModuleRef) {}
}

Récupération des instances

L’instance ModuleRef (ci-après appelée référence du module) a une méthode get(). Par défaut, cette méthode renvoie un fournisseur, un contrôleur ou un injectable (par exemple, garde, intercepteur, etc.) qui a été enregistré et qui a été instancié dans le module courant en utilisant son jeton d’injection ou son nom de classe. Si l’instance n’est pas trouvée, une exception sera levée.

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
private service: Service;
constructor(private moduleRef: ModuleRef) {}
onModuleInit() {
this.service = this.moduleRef.get(Service);
}
}

Résolution des fournisseurs scoped

Pour résoudre dynamiquement un fournisseur scoped (transitoire ou à la demande), utilisez la méthode resolve(), en passant le jeton d’injection du fournisseur comme argument.

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
private transientService: TransientService;
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
this.transientService = await this.moduleRef.resolve(TransientService);
}
}

La méthode resolve() renvoie une instance unique du fournisseur, à partir de son propre sous-arbre de conteneur DI. Chaque sous-arbre a un identifiant de contexte unique. Ainsi, si vous appelez cette méthode plusieurs fois et comparez les références d’instance, vous constaterez qu’elles ne sont pas égales.

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
const transientServices = await Promise.all([
this.moduleRef.resolve(TransientService),
this.moduleRef.resolve(TransientService),
]);
console.log(transientServices[0] === transientServices[1]); // false
}
}

Pour générer une seule instance lors de plusieurs appels à resolve(), et assurer qu’elles partagent le même sous-arbre de conteneur DI généré, vous pouvez passer un identifiant de contexte à la méthode resolve(). Utilisez la classe ContextIdFactory pour générer un identifiant de contexte.

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
const contextId = ContextIdFactory.create();
const transientServices = await Promise.all([
this.moduleRef.resolve(TransientService, contextId),
this.moduleRef.resolve(TransientService, contextId),
]);
console.log(transientServices[0] === transientServices[1]); // true
}
}

Enregistrement du fournisseur REQUEST

Les identifiants de contexte générés manuellement (avec ContextIdFactory.create()) représentent des sous-arbres DI dans lesquels le fournisseur REQUEST est undefined car ils ne sont pas instanciés et gérés par le système d’injection de dépendance de Nest. Pour enregistrer un objet REQUEST personnalisé pour un sous-arbre DI créé manuellement, utilisez la méthode ModuleRef#registerRequestByContextId() comme suit :

cats.service.ts
const contextId = ContextIdFactory.create();
this.moduleRef.registerRequestByContextId(/* YOUR_REQUEST_OBJECT */, contextId);

Obtention de l’arbre actuel

Occasionnellement, vous souhaiterez peut-être résoudre une instance d’un fournisseur scoped à la demande dans un contexte de demande. Supposons que CatsService soit scoped à la demande et que vous souhaitiez résoudre l’instance CatsRepository qui est également marquée comme fournisseur scoped à la demande. Pour partager le même sous-arbre de conteneur DI, vous devez obtenir l’identifiant de contexte actuel au lieu de générer un nouveau (par exemple, avec la fonction ContextIdFactory.create(), comme montré ci-dessus). Pour obtenir l’identifiant de contexte actuel, commencez par injecter l’objet de demande en utilisant le décorateur @Inject().

cats.service.ts
@Injectable()
export class CatsService {
constructor(
@Inject(REQUEST) private request: Record<string, unknown>,
) {}
}

Maintenant, utilisez la méthode getByRequest() de la classe ContextIdFactory pour créer un identifiant de contexte basé sur l’objet de demande, et passez cela à l’appel de resolve() :

cats.service.ts
const contextId = ContextIdFactory.getByRequest(this.request);
const catsRepository = await this.moduleRef.resolve(CatsRepository, contextId);

Instanciation dynamique de classes personnalisées

Pour instancier dynamiquement une classe qui n’a pas été précédemment enregistrée en tant que fournisseur, utilisez la méthode create() de la référence de module.

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
private catsFactory: CatsFactory;
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
this.catsFactory = await this.moduleRef.create(CatsFactory);
}
}

Cette technique vous permet d’instancier conditionnellement différentes classes en dehors du conteneur du framework.