Angular2 Инъекционные услуги в пользовательском ErrorHandler

У меня есть следующий код:

app.module.ts:

NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        RouterModule,
        BrowserModule,
        ReactiveFormsModule,
        FormsModule,
        HttpModule,
        AppRoutingModule // Routes
    ],
    providers: [ // services
        AppLog,
        {provide: ErrorHandler, useClass: MyErrorHandler}
    ],
    bootstrap: [AppComponent]
})
export class AppModule {}

MyErrorHandler.ts:

@Injectable()
export class MyErrorHandler implements ErrorHandler {
  constructor (private _appLog: AppLog) {}

  handleError(error:any):void {
    let errorMessage: string = "" + error
    this._appLog.logMessageAsJson(errorMessage, "error")
            .subscribe(
              ...
            )
  }
}

appLog.ts

@Injectable()
export class AppLog {
    constructor (private _http: Http) {}

    logMessageAsJson(message: string, type: string) {
        let headers = new Headers({ "Content-Type": "application/json" })
        let jsonMessage = {"type": type, "message": message}

        return this._http.post(JSON.stringify(jsonMessage), headers)
    }
}

Однако при загрузке моего приложения он терпит неудачу, если у меня есть инъекция в MyErrorHandler со следующей ошибкой:

Unhandled Promise rejection: Provider parse errors:
Cannot instantiate cyclic dependency!

Если я удалю constructor (private _appLog: AppLog) {}, а затем сделаю что-то еще в handleError, он будет работать нормально и вызывается ErrorHandler.

Я предполагаю, что это не работает, так как экземпляры экземпляра AppLog и MyErrorHandler выполняются одновременно

Ответ 1

Вы можете использовать это обходное решение для разложения циклических зависимостей с помощью DI

@Injectable()
export class MyErrorHandler implements ErrorHandler {
  private _appLog: AppLog;
  constructor (injector:Injector) {
    setTimeout(() => this._appLog = injector.get(AppLog));
  }
  ...
}

Углерод DI сам по себе не поддерживает циклические зависимости.

Ответ 2

ErrorHandler создается перед поставщиками. Итак, нам нужен Injector для внедрения зависимостей в наш собственный класс обработчика ошибок.

@Injectable()
export class MyErrorHandler implements ErrorHandler{
   constructor(private injector: Injector) { } 
  handleError(error: any) {
      let router = this.injector.get(ServiceName);

    }
}

Создайте службу по умолчанию через Angular cli и проверьте первую часть, см. providedIn: 'root',

@Injectable({
  providedIn: 'root',
})
export class CustomService{
  constructor(private otherService: OtherService) { // ok not failed } 
}

Для более детальной проверки угловых @Injectable-level configuration

@Инжекторы уровня NgModule Вы можете сконфигурировать провайдера на уровне модуля, используя опцию метаданных провайдеров для некорневого NgModule, чтобы ограничить область действия провайдера этим модулем. Это эквивалентно указанию некорневого модуля в метаданных @Injectable(), за исключением того, что служба, предоставляемая через провайдеров, не может быть преобразована в дерево.