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(), за исключением того, что служба, предоставляемая через провайдеров, не может быть преобразована в дерево.