简体   繁体   中英

How to load config.json and use the configuration values in another module?

I'm trying to move all configuration values from environment.ts to config.json , so I can use the same build for multiple different environments (development, staging and production).

I have been following the suggestion written in here, VSTS build - replace Angular4 environment variables in Release stage but in my case, I'm using some of the configuration values in another module, namely core.module which I'm setting up Azure MSAL details like Client Id, redirect Uri, etc.

I'm hitting an error saying that the configuration values that I need for setting up Azure MSAL are not yet loaded up.

config.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Config } from 'src/app/model/config';

export let CONFIG: Config;

@Injectable()
export class ConfigService {

  constructor(private http: HttpClient) { }

  public load() {
    return new Promise((resolve, reject) => {
      this.http.get('/assets/config/config.json')
        .subscribe((envResponse: any) => {
          const t = new Config();
          CONFIG  = Object.assign(t, envResponse);
          resolve(true);
        });

    });
  }
}

export function configFactoryService(configService: ConfigService): Function {
  return () => configService.load();
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { LOCALE_ID, NgModule, APP_INITIALIZER } from '@angular/core';

// Load the required calendar data for the de locale
import '@progress/kendo-angular-intl/locales/en-DK/all';

import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { routingModule } from './app.routing';
import { CoreModule } from './core/core.module';
import { SharedModule } from './shared/shared.module';
import { HomeModule } from './modules/home/home.module';
import { ConfigService, configFactoryService } from './core/services/config.service';
import { HttpClient, HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    BrowserAnimationsModule,
    HomeModule,
    SharedModule,
    CoreModule,
    routingModule,
    HttpClientModule
  ],
  providers: [
    ConfigService,
    {
      provide: APP_INITIALIZER,
      useFactory: configFactoryService,
      deps: [
        ConfigService,
        HttpClient
      ],
      multi: true
    },
    { provide: LOCALE_ID, useValue: 'en-DK' }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

core.module.ts

import { NgModule } from '@angular/core';
import { NavigationComponent } from './components/navigation/navigation.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';
import { HttpModule } from '@angular/http';
import { AuthMSALCustomInterceptor } from './interceptors/auth.msal.custom.interceptor';
import { MsalModule } from '@azure/msal-angular';
import { CONFIG as environment } from './services/config.service';
import { CommonModule } from '@angular/common';

@NgModule({
  imports: [
    CommonModule,
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule,
    RouterModule,
    HttpModule,
    MsalModule.forRoot({
      clientID: environment.clientID,
      authority: environment.authority,
      validateAuthority: true,
      redirectUri: environment.redirectUri,
      popUp: false,
      consentScopes: [
        `api://${environment.sApplicationId}/access_as_user`,
        `api://${environment.wApplicationId}/access_as_user`,
        `api://${environment.oApplicationId}/access_as_user`,
      ],
      protectedResourceMap: [
        [
          environment.sUrl,
          [`api://${environment.sApplicationId}/access_as_user`]
        ],
        [
          environment.wUrl,
          [`api://${environment.wApplicationId}/access_as_user`]
        ],
        [
          environment.oUrl,
          [`api://${environment.oApplicationId}/access_as_user`]
        ]
      ]
    })
  ],
  exports: [
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule,
    HttpModule,
    NavigationComponent
  ],
  declarations: [NavigationComponent],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthMSALCustomInterceptor,
      multi: true
    }
  ],
})
export class CoreModule { }

I need to be able to load the configuration values and use them in core.module . Is there a way to load config.json values even before the modules are initialized?

EDIT: A screenshot to show where the error occurs - core.module error

After a good amount of digging including the original blog post in this link, I landed on an implementation in the comments ( https://link.medium.com/QleSbGcCb7 ) that I liked the most, it's relatively simple and easy to follow. Hope this helps. See the link for full implementation, but here's the gist. Note that you'll need a config file and a model for you config.

fetch('./config.json')
  .then((response) => response.json())
  .then((config: ShellModuleConfig) => {
     if (environment.production) {
        enableProdMode();
     }

    platformBrowserDynamic(
      [{ provide: SHELL_RUNTIME_CONFIG, useValue: config }]
    )
    .bootstrapModule(AppModule)
    .catch((err) => console.error(err));
  });

The question is a little old but a similar issue may happen to others. The problem is that you are injecting HttpClient and as a result Angular needs to resolve all the HTTP_INTERCEPTORS first. This also means that MsalInerceptor is loaded and thus the MsalService is loaded before APP_INITIALIZER and therefore has no config loaded.

What you need to do is get rid off injection of HttpClient. Instead inject HttpBackend (make sure you use HttpBackend not HttpHandler) and create HttpClient locally. See the full example in this GitHub issue: https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/1403

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM