Нет провайдера для ConnectionBackend при наследовании от Http

Я пытаюсь создать оболочку для встроенной службы Http в angular 2, чтобы иметь возможность добавлять собственное поведение (заголовки, параметры и т. д.).

Поэтому я создал обычный класс (не сервис) и наследовал его от Http. Определение класса

import {
  Http,
  ConnectionBackend,
  RequestOptions,
  RequestOptionsArgs,
  Headers
} from '@angular/http';
import { Observable } from 'rxjs/Observable';
import {tamamApiUrl} from '../constants';
import {CustomQueryEncoder} from './CustomQueryEncoder';
import 'rxjs/Rx';

export class BaseHttp extends Http {
  protected applicationDataService;
  protected baseUrl: string = tamamApiUrl;
  protected encoder: CustomQueryEncoder;

  constructor(backend:ConnectionBackend,
              defaultOptions: RequestOptions, applicationDataService: any) {
    super(backend, defaultOptions);
    this.applicationDataService = applicationDataService;
  }


  get(url: string, options?: RequestOptionsArgs): Observable<any> {
    this.addDefaultOptions(options);
    return super.get(url, options);
  }

  post(url: string, body: any, options?: RequestOptionsArgs): Observable<any> {
    this.addDefaultOptions(options);
    this.addDefaultPostOptions(options);
    return super.post(url, body, options);
  }

  private addDefaultOptions(options?: RequestOptionsArgs): RequestOptionsArgs {
    if (options == null) {
      options = new RequestOptions();
    }
    if (options.headers == null) {
      options.headers = new Headers();
    }
    const applicationData = this.applicationDataService.getApplicationData();

    if (applicationData.applicationKey) {
      options.headers.append('application-id', applicationData.applicationKey);
    }

    if (applicationData.secretKey) {
      options.headers.append('secret-key', applicationData.secretKey);
    }

    if (applicationData.userToken) {
      options.headers.append('user-token', applicationData.userToken);
    }

    return options;
  }

  private addDefaultPostOptions(options): void {
    options.headers.append('Content-Type', 'application/json');
  }

  /*private requestInterceptor(): void {
    this.loaderService.showPreloader();
  }


  private responseInterceptor(): void {
    this.loaderService.hidePreloader();
  }*/
}

Затем я создал службу, унаследованную от этого класса, чтобы я мог внедрить ее позже и использовать для своих целей.

import { Headers, URLSearchParams } from '@angular/http';
import {tamamRootUrl} from '../constants';
import {BaseHttp} from '../api/BaseHttp';
import { Injectable } from '@angular/core';
import {
  ConnectionBackend,
  RequestOptions,
} from '@angular/http';
import {ApplicationService} from './ApplicationService';

@Injectable()
export class InspectionHttpService extends BaseHttp{

  protected baseUrl: string = tamamRootUrl;
  protected params: URLSearchParams = new URLSearchParams();

  constructor(backend: ConnectionBackend,
              defaultOptions: RequestOptions, protected applicationService: ApplicationService) {
    super(backend, defaultOptions, applicationService);
  }

  getRootUrl() {
    return this.baseUrl;
  }
}

Определение службы

После того, как я пытаюсь внедрить созданный сервис в компонент, я получаю сообщение об ошибке:

error_handler.js:47 ИСКЛЮЧЕНИЕ: неперехвачено (в промисе): ошибка: ошибка в классе ./VehiclesListComponent VehiclesListComponent_Host — встроенный шаблон: 0:0, вызванный: нет поставщика для ConnectionBackend!

Я попытался найти решение с помощью stack-overflow, но вижу, что HtpModule уже должен иметь все необходимое для правильной работы.

Кто-нибудь может мне помочь? В чем проблема?


person Nick Shulzhenko    schedule 09.11.2016    source источник
comment
Также я использовал эту ссылку в качестве примера наследования от Http: blog.tomasandtomas.com/   -  person Nick Shulzhenko    schedule 09.11.2016
comment
Пожалуйста, добавьте код в виде текста в вопрос, а не ссылку на скриншоты.   -  person Günter Zöchbauer    schedule 09.11.2016
comment
Форматирует очень странно, но я попробую.   -  person Nick Shulzhenko    schedule 09.11.2016
comment
Просто выберите код и нажмите кнопку {} на панели инструментов редактора (или используйте любой другой способ, чтобы каждая строка кода начиналась как минимум с 4 пробелов)   -  person Günter Zöchbauer    schedule 09.11.2016
comment
Намного лучше, но это была не та кнопка. Фрагменты [<>] предназначены только для кода, который действительно может быть выполнен внутри вопроса, [{}] — для кода, который не может быть запущен.   -  person Günter Zöchbauer    schedule 09.11.2016


Ответы (2)


Вы не можете просто добавить его к поставщикам, как это

providers: [ ApplicationService, InspectionHttpService ]

Если вы это сделаете, Angular попытается создать его и не найдет провайдера для ConnectionBackend.

Вам нужно использовать фабрику, где вы можете просто передать XHRBackend (который реализует ConnectionBackend)

imports: [HttpModule],
providers: [
  ApplicationService,
  {
    provide: InspectionHttpService,
    deps: [XHRBackend, RequestOptions, ApplicationService],
    useFactory: (backend, options, aplicationService) => {
      return new InspectionHttpService(backend, options, applicationService);
    }
  }
]

При этом вы можете ввести его как InspectionHttpService.

constructor(private http: InspectionHttpService) {}

Если вы хотите иметь возможность вводить его как Http, вам нужно изменить provide на Http вместо InspectionHttpService. Но это отменяет любую возможность использовать обычный Http, если он вам когда-нибудь понадобится.

ОБНОВИТЬ

В некоторых средах возможно появление ошибки с приведенным выше кодом. Я забыл точное сообщение об ошибке, но оно даст вам предлагаемое решение по извлечению фабричной функции, т.е.

export function httpFactory(backend: XHRBackend, options: RequestOptions,
                            service: ApplicationService) {
  return new InspectionHttpService(backend, options, service);
}

useFactory: httpFactory

Насколько я помню, ошибка как-то связана с AoT.

person Paul Samsotha    schedule 09.11.2016
comment
Мужик, ты фантастический! Вы сэкономили мое время. Но все же откуда я мог это знать? Я думаю, что нам все еще нужна лучшая документация, или я что-то потерял, изучая DI в angular2. Большое спасибо за такой быстрый ответ! Хорошего дня, надеюсь у тебя все хорошо) - person Nick Shulzhenko; 09.11.2016
comment
Я получаю сообщение об ошибке «Нет провайдера для XHRBackend» — мысли? - person josh-sachs; 05.03.2017
comment
@Kudoz Вам все еще нужно импортировать HttpModlule - person Paul Samsotha; 05.03.2017
comment
Он импортирован ... Я думаю, что проблема как-то связана с тем, когда я импортирую свой расширенный класс HTTP. Я предоставляю его в начальной загрузке - кажется, работает, если я предоставляю его как часть ngModule. - person josh-sachs; 06.03.2017

При расширении службы Http вам необходимо внедрить бэкэнд и параметры для родительского класса:

@Injectable()
export class HttpInterceptor extends Http {
  constructor(
    backend: XHRBackend,
    options: RequestOptions,
    ...
  ) {
    super(backend, options);
  }
  ...
}

Таким образом, вам не нужно использовать фабрику, потому что Angular самостоятельно вычислит инъекцию.

person gabo bernal    schedule 15.09.2017