No provider for ConnectionBackend while inheriting from Http

元气小坏坏 提交于 2019-11-28 02:52:06

问题


I am trying to make a wrapper around built in Http service in angular 2 to have a possibility to add custom behaviour (headers, parameters etc.)

So I created a usual class (not a service) and inherit it from Http. Class definition

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();
  }*/
}

Than I Created a service which inherited from this class so that I can inject it later and use for my purposes.

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;
  }
}

Service definition

After I try to inject created service in component I receive an error:

error_handler.js:47 EXCEPTION: Uncaught (in promise): Error: Error in ./VehiclesListComponent class VehiclesListComponent_Host - inline template:0:0 caused by: No provider for ConnectionBackend!

I tried to search solution using stack-overflow but it see,s that HtpModule should already have all necessary for a proper work.

Could anyone help me? Where is the problem?


回答1:


You can't just add it to the providers like this

providers: [ ApplicationService, InspectionHttpService ]

If you do, then Angular will try to create it, and it won't find a provider for ConnectionBackend

You need to use a factory, where you can just pass the XHRBackend (which implements ConnectionBackend)

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

With this, you can inject it as InspectionHttpService.

constructor(private http: InspectionHttpService) {}

If you want to be able to inject it as Http, then you need to change the provide to Http instead of InspectionHttpService. But this overrides any ability to use the regular Http if you ever need it.

UPDATE

In some environments, it's possible you may get an error with the above code. I forgot the exact error message, but it will give you a proposed solution of extracting the factory function, i.e.

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

useFactory: httpFactory

From what I remember, I think the error has something to do with AoT




回答2:


When extending the Http service, you have to inject backend and options for the parent class:

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

This way you don't have to use a factory because Angular will figure the injection on its own.



来源:https://stackoverflow.com/questions/40507670/no-provider-for-connectionbackend-while-inheriting-from-http

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!