Механизм внедрения зависимостей на клиенте

В данном разделе рассмотрены особенности передачи клиентских сервисов с использованием механизма внедрения зависимостей.

У сервиса имеется имя и интерфейс. Например, сервис для получения информации о текущей карточке имеет имя $CardInfo, и интерфейс GenModels.CardInfoModel. Получить сервис можно по имени при помощи метода getService у объекта элемента управления, разметки или глобального объекта app. Например, таким образом можно получить сервис $CardInfo в обработчике события:

export function onCustomButtonClick(sender: CustomButton, args: IEventArgs) {
     const cardInfo = sender.getService($CardInfo);
}

Сервисы, как правило, размещаются в контейнерах — специальных объектах. Имя сервиса — это ключ, по которому данный сервис можно получить в сервис-контейнере. Получить сервис-контейнер можно вызвав getService без параметров. Так альтернативный способ получения сервиса по ключу из контейнера будет выглядеть так:

export function onCustomButtonClick(sender: CustomButton, args: IEventArgs) {
     const cardInfo = sender.getService()[$CardInfo] as GenModels.CardInfoModel; (1)
     const cardInfo2 = sender.getService<$CardInfo>().cardInfo; (2)
}
1 Получаем либо по ключу
2 Либо иным образом

Сервис-контейнер уровня приложения доступен через глобальный объект app, однако его не рекомендуется использовать в большинстве случаев.

Сервис контейнер в элементах управления также доступен через параметр services (он же props при отрисовке элемента управления как React-компонента).

Все стандартные сервисы Web-клиента (приведены в JSDoc API).

Создание сервисов

Определение сервиса включает в себя три составляющих:
  • Описание интерфейса сервиса и его имени.

  • Определение реализации.

  • Регистрация реализации.

    1. Первое, что нужно сделать — выбрать название сервиса. Допустим, наш сервис будет называться Greeting. Тогда описание интерфейса и имени сервиса будет выглядеть следующим образом:

      export interface IGreetingService {
           showGreeting(name: string): Promise<void>;
      }
      export type $Greeting = { greeting: IGreetingService };
      export const $Greeting = serviceName<$Greeting, IGreetingService>(x => greeting);
    2. Реализацию сервиса рекомендуется определять в отдельном от интерфейса файле (чтобы не создавать лишние зависимости). Реализацией будет определение класса, реализующего интерфейс IGreetingService.

      export class GreetingSevice implements IGreetingService {
            constructor(private services: $MessageWindow) {
            }
            showGreeting(name: string): Promise<void>{
                  return this.services.messageWindow.showInfo("Добро пожаловать, " + name);
            }
       }
    3. Регистрируются сервисы в файле Index.ts веб-расширения через вызов registerExtension. Если сервис имеет отношение к разметке, то следует передавать его в поле layoutServices, иначе в globalServices.

      extensionManager.registerExtension({
            name: "Greeting",
            version: "1.0",
            layoutServices: [
                 Service.fromFactory($Greeting,
                      (services: $StandardServices & $StandardControllers) =>
                            new GreetingSevice(services))
            ]
      })