简体   繁体   中英

Can't inject service from my dynamic module into "registerAsync" of another module in NestJS

I created my own dynamic module to setup file upload for my project.

But when I try to inject service from my module in registerAsync method of MulterModule, I get this error:

Error: Nest can't resolve dependencies of the MULTER_MODULE_OPTIONS (?). Please make sure that the argument UploadsService at index [0] is available in the MulterModule context.

Potential solutions:
- If UploadsService is a provider, is it part of the current MulterModule?
- If UploadsService is exported from a separate @Module, is that module imported within MulterModule?
  @Module({
    imports: [ /* the Module containing UploadsService */ ]
  })
        UploadsModule.forRoot({
            endpoint: process.env.S3_ENDPOINT,
            accessKey: process.env.S3_ACCESS_KEY,
            secretKey: process.env.S3_SECRET_KEY,
            bucket: 'testbucket',
        }),
        MulterModule.registerAsync({
            imports: [UploadsModule],
            inject: [UploadsService],
            useFactory: (uploadsService: UploadsService) => ({
                storage: uploadsService.getS3MulterStorage(),
            }),
        }),

I followed this guide from NestJS Docs and code of my UploadsModule is:

import { DynamicModule, Module } from '@nestjs/common';
import { UploadsService } from './uploads.service';
import { UploadsModuleOptions } from './uploads.types';

@Module({})
export class UploadsModule {
    static forRoot(options: UploadsModuleOptions): DynamicModule {
        return {
            module: UploadsModule,
            providers: [
                {
                    provide: 'UPLOADS_MODULE_OPTIONS',
                    useValue: options,
                },
                UploadsService,
            ],
            exports: [UploadsService],
        };
    }
}

And this is code of my UploadsService:

@Injectable()
export class UploadsService {
    private readonly client: S3Client;
    private readonly bucket: string;
    private readonly multerStorage: StorageEngine;

    constructor(
        @Inject('UPLOADS_MODULE_OPTIONS')
        private readonly options: UploadsModuleOptions,
    ) {
        this.client = new S3Client({
            endpoint: options.endpoint,
            credentials: {
                accessKeyId: options.accessKey,
                secretAccessKey: options.secretKey,
            },
        });
        this.bucket = options.bucket;
        this.multerStorage = multerS3({
            s3: this.client,
            bucket: this.bucket,
            acl: 'private',
            metadata: (req, file, cb) => {
                cb(null, { fieldName: file.fieldname });
            },
            key: (req, file, cb) => {
                cb(null, file.originalname + '-' + Date.now());
            },
        });
    }

    getS3MulterStorage() {
        return this.multerStorage;
    }
}

UploadsModule exports UploadsService, registerAsync method of MulterModule imports my UploadsModule and therefore must be able to inject UploadService?

Only your UploadsModule.forRoot() provides the exports of UploadsService , so when you use imports: [UploadsModule] you don't get the same providers exported. What I would suggest is create a separate module that does and import and export of the UploadsModule so you can import the wrapper and make use of module re-exporting

@Module({
  imports: [UploadsModule.forRootAsync(uploadModuleOptions)],
  exports: [UploadsModule]
})
export class WrapperUploadsModule {}
MulterModule.registerAsync({
  imports: [WrapperUploadsModule],
   inject: [UploadsService],
   useFactory: (uploadsService: UploadsService) => ({
     storage: uploadsService.getS3MulterStorage(),
   }),
}),

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM