【问题标题】:NestJS Nest can't resolve dependencies of the RolesService (+, +, ?)NestJS Nest 无法解析 RolesService 的依赖项(+、+、?)
【发布时间】:2019-01-21 13:56:33
【问题描述】:

您好,我正在使用 NestJS 框架(使用 MongoDB)进行编程,现在已经构建了一些模块。当我尝试从另一个模块导入模型时,它返回此错误:

Nest 无法解析 RolesService 的依赖项(+、+、?)。

现在,我已经实现了这样的代码:

app.module.ts

import { GroupsModule } from './groups/groups.module';
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UsersModule } from 'users/users.module';
import { RolesModule } from 'roles/roles.module';

@Module({
  imports: [
          MongooseModule.forRoot('mongodb://localhost:27017/example'),
          UsersModule,
          GroupsModule,
          RolesModule,
        ],
  providers: [],
})
export class AppModule {}

users.module.ts

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';

import { UsersController } from './users.controller';

import { UsersService } from './users.service';
import { RolesService } from 'roles/roles.service';

import { UserSchema } from './schemas/user.schema';
import { RoleSchema } from 'roles/schemas/role.schema';

@Module({
    imports: [
      MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
      MongooseModule.forFeature([{ name: 'Role', schema: RoleSchema }]),
    ],
    controllers: [UsersController],
    providers: [UsersService, RolesService],
    exports: [UsersService],
  })

export class UsersModule {}

users.service.ts

import { Model } from 'mongoose';
import { ObjectID } from 'mongodb';
import { InjectModel } from '@nestjs/mongoose';
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';

import { User } from './interfaces/user.interface';

@Injectable()
export class UsersService {
  constructor(@InjectModel('User') private readonly userModel: Model<User>) {}
}

groups.module.ts

import { MongooseModule } from '@nestjs/mongoose';

import { GroupsController } from './groups.controller';

import { RolesService } from '../roles/roles.service';
import { GroupsService } from './groups.service';

import { GroupSchema } from './schemas/group.schema';
import { UserSchema } from '../users/schemas/user.schema';
import { RoleSchema } from '../roles/schemas/role.schema';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: 'Group', schema: GroupSchema }]),
    MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
    MongooseModule.forFeature([{ name: 'Role', schema: RoleSchema }]),
  ],
  controllers: [GroupsController],
  providers: [GroupsService, RolesService],
  exports: [GroupsService],
})

groups.service.ts

import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { ObjectID } from 'mongodb';
import { Model } from 'mongoose';

import { Group } from './interfaces/group.interface';
import { User } from '../users/interfaces/user.interface';

import { CreateGroupDto } from './dto/create-group.dto';
import { RolesDto } from 'roles/dto/roles.dto';
import { Role } from '../roles/interfaces/role.interface';

@Injectable()
export class GroupsService {
    constructor(@InjectModel('Group') private readonly groupModel: Model<Group>,
                @InjectModel('Role') private readonly roleModel: Model<Role>) {} }

roles.module.ts

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';

import { RolesController } from './roles.controller';

import { RolesService } from './roles.service';

import { RoleSchema } from './schemas/role.schema';
import { UserSchema } from '../users/schemas/user.schema';
import { GroupSchema } from '../groups/schemas/group.schema';

@Module({
    imports: [
      MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
      MongooseModule.forFeature([{ name: 'Role', schema: RoleSchema }]),
      MongooseModule.forFeature([{ name: 'Group', schema: GroupSchema }]),
    ],
    controllers: [RolesController],
    providers: [RolesService],
    exports: [RolesService],
  })

export class RolesModule {}

roles.service.ts

import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { ObjectID } from 'mongodb';
import { Model } from 'mongoose';

import { Role } from './interfaces/role.interface';
import { User } from '../users/interfaces/user.interface';
import { Group } from '../groups/interfaces/group.interface';

import { CreateRoleDto } from './dto/create-role.dto';
import { RolesDto } from './dto/roles.dto';

@Injectable()
export class RolesService {
    constructor( @InjectModel('Role') private readonly roleModel: Model<Role>,
                 @InjectModel('User') private readonly userModel: Model<User>,
                 @InjectModel('Group') private readonly groupModel: Model<Group> ) {} }

虽然用户和角色中的 DI 工作正常,但当我尝试在角色服务中导入组模型时出现错误。如果您发现任何错误,请告诉我,我已从用户组中遵循相同的架构,但遗憾的是看不到错误所在。

提前致谢。

更新:好的,我认为我的错误是当我尝试在模块外使用模块服务功能时。我的意思是我修改了(为了简化)我会这样修改代码:

users.module.ts

@Module({
    imports: [
      MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
      RolesModule,
    ],
    controllers: [UsersController],
    providers: [UsersService, RolesService],
    exports: [UsersService],
  })

export class UsersModule {}

users.controller.ts

export class UsersController {

    constructor(private readonly usersService: UsersService,
                private readonly rolesService: RolesService){}

    async addRoles(@Param('id') id: string, @Body() userRolesDto: UserRolesDto): Promise<User> {
        try {
            return this.rolesService.setRoles(id, userRolesDto);
        } catch (e){
            const message = e.message.message;
            if ( e.message.error === 'NOT_FOUND'){
                throw new NotFoundException(message);
            } else if ( e.message.error === 'ID_NOT_VALID'){
                throw new BadRequestException(message);
            }
        }

    }

}

roles.module.ts

@Module({
    imports: [
      MongooseModule.forFeature([{ name: 'Role', schema: RoleSchema }]),
    ],
    controllers: [RolesController],
    providers: [RolesService],
    exports: [RolesService],
  })

export class RolesModule {}

roles.service.ts

@Injectable()
export class RolesService {
    userModel: any;
    constructor( @InjectModel('Role') private readonly roleModel: Model<Role> ) {}

    // SET USER ROLES
    async setRoles(id: string, rolesDto: RolesDto): Promise<User> {
        if ( !ObjectID.isValid(id) ){
            throw new HttpException({error: 'ID_NOT_VALID', message: `ID ${id} is not valid`, status: HttpStatus.BAD_REQUEST}, 400);
        }
        try {
            const date = moment().valueOf();
            const resp = await this.userModel.updateOne({
              _id: id,
            }, {
              $set: {
                  updated_at: date,
                  roles: rolesDto.roles,
              },
            });
            if ( resp.nModified === 0 ){
              throw new HttpException({ error: 'NOT_FOUND', message: `ID ${id} not found or entity not modified`, status: HttpStatus.NOT_FOUND}, 404);
            } else {
              let user = await this.userModel.findOne({ _id: id });
              user = _.pick(user, ['_id', 'email', 'roles', 'created_at', 'updated_at']);
              return user;
            }
        } catch (e) {
          if ( e.message.error === 'NOT_FOUND' ){
            throw new HttpException({ error: 'NOT_FOUND', message: `ID ${id} not found or entity not modified`, status: HttpStatus.NOT_FOUND}, 404);
          } else {
            throw new HttpException({error: 'ID_NOT_VALID', message: `ID ${id} is not valid`, status: HttpStatus.BAD_REQUEST}, 400);
          }
        }
    }

就是这样,当我尝试从 users.controller 使用 roles.service setRole 方法时,您可以看到它返回一个错误:

Nest 无法解析 RolesService (?) 的依赖关系。请确保索引 [0] 处的参数在当前上下文中可用。

我不明白问题出在哪里,因为我已经在 roles.module 中注入了 Role 模型并且它不理解它。事实上,如果我不创建从 users.module 到此依赖项的调用,一切都会好起来的。

有什么建议吗?

(我已经把stackoverflow的建议加红了,我不会再这样做了)

【问题讨论】:

    标签: javascript node.js dependency-injection dependencies nestjs


    【解决方案1】:

    我认为问题在于您多次导入同一个模型,例如:

    MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]
    

    并且还多次提供相同的服务:

    providers: [RolesService]
    

    我不会注入模型本身,而是注入封装模型的相应服务。然后你 export 模块中的服务并在需要的地方导入模块。所以RolesService 会注入UsersSerivce 而不是UserModel

    使用您当前的设置,您会遇到循环依赖。这可以通过fowardRef(() =&gt; UserService) 处理,但应尽可能避免,请参阅circular dependency docs。但是,这是否可以避免取决于您的业务逻辑。

    如果你没有循环依赖,那么例如导出你的RolesService

    @Module({
        imports: [MongooseModule.forFeature([{ name: 'Role', schema: RoleSchema }])]
        controllers: [RolesController],
        providers: [RolesService],
        exports: [RolesService],
      })
    
    export class RolesModule {}
    

    并在您想使用RolesService 的任何地方导入RolesModule,例如:

    @Module({
        imports: [
          RolesModule,
          MongooseModule.forFeature([{ name: 'User', schema: UserSchema }])
        ],
        controllers: [UsersController],
        providers: [UsersService],
        exports: [UsersService],
      })
    

    【讨论】:

    • 感谢 Kim,我一直在尝试按照您的评论进行操作,但不幸的是我找不到解决方案。我确实尝试只调用一次您评论的行,然后从需要它的模块中调用它(例如 RolesService )。在这种情况下,如果你能告诉我如何实现它,应该会很有帮助。我不会使用循环依赖,我已经红色了很多文档但找不到解决方案......(现在有点绝望)
    • 很难说你应该如何实现它,因为我不知道你想要实现什么。我只能假设您想检查用户是否具有特定角色。您可以查看文档中的RolesGuard example。在这种情况下,他们将角色附加到响应中的授权用户(例如来自 JWT)。
    • 嗨,Kim 再次感谢您的回答,抱歉,我无法理解 DI 的工作方式(我已经阅读了数百万次文档)。但它在某些情况下对我有用,而在其他情况下则不行。特别是当我从另一个模块导入一个模块时,它似乎无法识别自己导入的东西。抱歉,我的要求可能有点令人困惑......我发现nestjs 是一个很棒的框架,但在这个意义上有点“模糊”(或者可能是我对它缺乏了解)无论如何谢谢
    • 当你导入一个模块时,它只会导入导出的提供者。如果您在问题中更新代码,我会再看一遍。也可以考虑stackoverflow.com/help/someone-answers :-)
    • 从 UserModule 的 providers 数组中移除 RolesService。您正在导入模块及其所有导出的提供程序。如果您再次提供 RolesService,它将查找其依赖项(Roles 模型),而不是在 UsersModule 中找到它。
    猜你喜欢
    • 1970-01-01
    • 2020-08-12
    • 2023-04-01
    • 2020-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-05
    • 2021-09-06
    相关资源
    最近更新 更多