【问题标题】:Can I access the DI injector directly to instantiate classes with NestJS我可以直接访问 DI 注入器以使用 NestJS 实例化类吗
【发布时间】:2019-10-19 21:12:19
【问题描述】:

我想知道是否有一种方法可以访问 NestJS 中的 DI 注入器并直接使用它来实例化类。这类似于 Angular 或 Inversify 如何在特殊情况下直接公开注入器。

多供应商可以解决我的用例。但是,在 NestJS 支持多提供者之前,我改为尝试创建一个复合守卫,将多个守卫捆绑在一起,以便我可以全局应用多个需要访问 DI 的守卫。我希望复合守卫只接收一个类型数组,然后使用注入器为这些类型填充对象。

我尝试将 Injector 指定为工厂依赖项,但 Nest 无法解决它。如果它确实解决了,我不知道我将如何使用注射器。

@Module({
    providers: [{
        provide: APP_GUARD,
        inject: [Injector],
        useFactory: (injector: Injector) => {
            return new MultiGuard([AuthGuard, PermissionGuard], injector);
        }
    }]
})
class AppModule {}
import { CanActivate, ExecutionContext, Type } from '@nestjs/common';

export class MultiGuard implements CanActivate {
    constructor(
        private readonly guards: Type<CanActivate>[],
        private readonly injector: Injector
    ) {}

    async canActivate(context: ExecutionContext): Promise<boolean> {
        const guards = this.guards.map(guard => {
            return this.injector.get(guard);
        });

        const results = await Promise.all(guards);

        return results.every(r => !!r);
    }
}

【问题讨论】:

    标签: typescript dependency-injection nestjs


    【解决方案1】:

    我最近做了类似的事情,但是我没有将守卫类型传递给我的“多重守卫”,而是在工厂中实例化守卫并传递一组守卫实例。

    这与 NestJS 执行守卫的方式非常相似。查看guard-consumer.ts 文件。

    https://github.com/nestjs/nest/blob/master/packages/core/guards/guards-consumer.ts

    @Injectable()
    export class GuardsCollection implements CanActivate {
      public constructor(private readonly guards: CanActivate[]) {}
    
      public async canActivate(context: ExecutionContext): Promise<boolean> {
        for (const guard of this.guards) {
          const result = guard.canActivate(context);
          if (!(await this.pickResult(result))) {
            return false;
          }
        }
    
        return true;
      }
    
      private async pickResult(result: boolean | Promise<boolean> | Observable<boolean>): Promise<boolean> {
        if (result instanceof Observable) {
          return result.toPromise();
        }
        return result;
      }
    }
    

    在工厂中,我实例化了我的守卫。如果我的守卫有任何依赖关系,我可以通过在 Inject 数组中指定依赖关系来解决它们。可选的 inject 属性接受 NestJS 将解析并在实例化过程中作为参数传递给工厂函数的提供程序数组。

    @Module({
      providers: [
        {
          provide: APP_GUARD,
          useFactory: (reflector: Reflector) => {
            return new GuardsCollection([
              new (AuthGuard('jwt'))(),
              new RolesGuard(reflector),
            ]);
          },
          inject: [Reflector],
        },
      ],
    })
    export class AuthModule {}
    

    另一个可能的选择是注入ModuleRef 并使用它来解析当前模块上下文中的项目。只要将另一个模块导入到当前模块中,您也应该能够从另一个模块获取项目。

    @Injectable()
    export class MyGlobalGuard implements CanActivate {
      public constructor(private readonly moduleRef: ModuleRef) {}
    
      public async canActivate(context: ExecutionContext): Promise<boolean> {
        // ... resolve items.
        return true;
      }
    }
    
    @Module({
      providers: [
        {
          provide: APP_GUARD,
          useClass: GlobalGuard,
        },
      ],
    })
    export class AuthModule {}
    

    【讨论】:

      猜你喜欢
      • 2021-08-26
      • 2020-08-30
      • 1970-01-01
      • 2011-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多