Динамическое обслуживание вызова - МОК - PullRequest
0 голосов
/ 31 октября 2019

как я могу динамически вызывать метод службы (поиск по хеш-карте) из контроллера:

registration.service.ts

import { Injectable } from '@nestjs/common';
import { CacheService } from '../cache/cache.service';
import { LoggerService } from '../../config/logger/logger.service';

@Injectable()
export class RegistrationService {

  constructor(private readonly cache: CacheService,
    private readonly logger: LoggerService) {
  }

  async process() {
    this.logger.info(`RegistrationService - testThis - hit!`);
  }

}

app.controller.ts

import { Controller, Get, Res } from '@nestjs/common';
import { RegistrationService } from './modules/campaignOne/registration.service';

const SCREENS = {
  'start': 'this.registration.process'
};

@Controller()
export class AppController {
  constructor(private readonly registration: RegistrationService) {}

  @Get('test')
  async test(@Res() res: any): any {
    await eval(SCREENS['start'])();
    return Promise.resolve('ok');    
  }
}

Когда выполняется await eval(SCREENS['start'])();, вызывается метод, но в this.logger.. выдается ошибка, поскольку он не может разрешить регистратор.

Идея состоит в том, чтобы иметь несколько провайдерови логика в контроллере будет определять, какой провайдер вызывать динамически.

Я знаю, что проблема и решение лежат в внедрении зависимостей и IOC - но я не знаю, как решить.

Помогите пожалуйста?

1 Ответ

1 голос
/ 31 октября 2019

Я бы использовал фабричный подход с этим.

Сначала создайте интерфейс для определения формы «динамического» сервиса, который вы хотите

//IService.ts

export interface IService {
    invoke(): Promise<void>;
}

Теперь все ваши сервисы, которые выхочу динамически реализовать этот интерфейс. ПРИМЕЧАНИЕ. Этот сервис не использует аннотацию nest @Injectable, потому что этот класс не является тем, что будет фактически внедрено, как вы увидите ниже.

//registration.service.ts

import { CacheService } from '../cache/cache.service';
import { LoggerService } from '../../config/logger/logger.service';

export class RegistrationService implements IService {

    private readonly cache: CacheService;
    private readonly logger: LoggerService;

    constructor(cache: CacheService, logger: LoggerService) {
        this.cache = cache;
        this.logger = logger;
    }

    async invoke() : Promise<void> {
        this.logger.info(`RegistrationService - testThis - hit!`);
        return Promise.resolve();
    }

}

Теперь создайте свой фабричный класс, который будет получатьВнедренный IOC

//ScreenFactory.ts

import { Injectable } from '@nestjs/common';
import { RegistrationService } from './modules/campaignOne/registration.service';

@Injectable()
export class ScreenFactory {

    private readonly cache: CacheService;
    private readonly logger: LoggerService;

    constructor(cache: CacheService, logger: LoggerService) {
        this.cache = cache;
        this.logger = logger;
    }

    public getService(screenName: string) : IService {

        switch(screenName) {
            case 'start': return new RegistrationService(this.cache, this.logger);
            default: throw new Error('No service defined for the given screen');
        }

    }
}

Теперь в вашем модуле вместо этого введите фабрику

import { Controller, Get, Res } from '@nestjs/common';
import { ScreenFactory } from './modules/ScreenFactory';

@Controller()
export class AppController {

    constructor(private readonly screenFactory: ScreenFactory) {}

    @Get('test')
    async test(@Res() res: any): any {

        //await eval(SCREENS['start'])();
        const service: IService = this.screenFactory.getService('start');
        await service.invoke();

        return Promise.resolve('ok');
    }
}

Это много псевдокода, но так я обычно обращаюсь: «Мне нужен другойтип сценария "вещь за запрос".

...