angulardependency-injectionangular2-servicesangular2-di

Angular 2 inject service into service


In my app, I have extended the Angular Http class with our own implementation that adds some headers.

export class Secure_Http extends Http {
    private getJwtUrl = environment.employerApiUrl + '/getJwt';
    private refreshJwtUrl = environment.employerApiUrl + '/refreshJwt';

    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private storage: SessionStorageService) {
        super(backend, defaultOptions);
    }

Then, in the app.mobule.ts file, I've done this so our secure version is used everytime instead of the base version:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    ....
  ],
  providers: [
    ....
    SessionStorageService,
    {
      provide: Http,
      useFactory: secureHttpFactory,
      deps: [XHRBackend, RequestOptions, SessionStorageService]
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

export function secureHttpFactory(backend: XHRBackend, options: RequestOptions, sessionStorage: SessionStorageService) {
    return new Secure_Http(backend, options, sessionStorage);
}

Now, in our services, we use the standard constructor/DI approach:

@Injectable()

export class MySecurityService {
    employerApiBaseUrl: string = environment.employerApiUrl;

    constructor(private _http: Http) { } //, private _secureHttp: Secure_Http

    getUser() : Observable<User> {
        this.log('getUser', 'getting the current user');

        var thisUrl = this.employerApiBaseUrl + '/jwt/userinfo';

        var searchParam = {
            jwt: this.getToken()
        };

        return this._http.post(thisUrl, searchParam)
            .map((response: Response) => this.extractGetUserResponse(response))
            .catch(this.handleError);
    }
}

Now my problem is, the SecurityService needs to also inject the Secure_Http class/service because there's one function on there that is needed to get the JWT.

But, as soon as I add the Secure_Http class/service as a constructor parameter, I get the error No provider for Secure_Http.

So, my next thought is to add the Secure_Http to the providers section in the app.module.ts file, right next to where I specify Http needs to use Secure_Http. But as soon as I do that, I then get the error No provider for ConnectionBackend. If I turn around and add ConnectionBackend into the providers, then there's an error on the @NgModule saying Type 'typeof ConnectionBackend' is not assignable to type provider.

Where am I going wrong here? I just have 1 method that I need to access on the Secure_Http class directly. That's needed because it needs to be a parameter for one of my post calls. I can't just call it from the Secure_Http service/class because the parameters have already been passed...


Solution

  • If you explicitly want to inject Secure_Http, you need to provide it

    {
      provide: Secure_Http,
      useFactory: secureHttpFactory,
      deps: [XHRBackend, RequestOptions, SessionStorageService]
    },
    { provide: Http, useExisting: Secure_Http }
    

    this way both lead to Secure_Http being injected

    constructor(private _http: Http) { } 
    constructor(private _secureHttp: Secure_Http) {}
    

    but if you know that Http injects Secure_http (as your configuration would do) you can just cast

    private _http: SecureHttp;
    constructor(http: Http) { 
      this._http = http as Secure_Http;
    }