【问题标题】:Angular 2 RC 2 How to Inject Router into Custom ExceptionHandlerAngular 2 RC 2 如何将路由器注入自定义 ExceptionHandler
【发布时间】:2016-06-17 10:46:30
【问题描述】:

我正在使用 Angular 2 RC2。我需要将 Angular 2 路由器注入到我的自定义 ExceptionHandler 类中。但是我收到以下错误

错误:错误:无法解析“ErrorHandler”(?)的所有参数。 确保所有参数都用 Inject 修饰或具有 有效的类型注释,并且“ErrorHandler”用 可注射。

我确实尝试装饰私有路由器:使用@Inject 的路由器无济于事。我使用的是打字稿,因此我认为这里不需要@Inject 属性。

我的自定义 ExceptionHandler 看起来像这样

import { ExceptionHandler } from '@angular/core';
import { Router } from '@angular/router';

export class ErrorHandler extends ExceptionHandler{

    constructor(
        private router: Router 
    ){
        super(null, null);

    }

    call(error, stackTrace = null, reason = null) {
        console.log(error);
        this.router.navigate(['/error']);
    }
}

我的 main.ts 是这样的

import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app.component';

import { provide, ExceptionHandler } from '@angular/core';
import { ErrorHandler } from './error-handler/error-handler';

import { HTTP_PROVIDERS } from '@angular/http';
import { ROUTER_PROVIDERS } from '@angular/router';

bootstrap(AppComponent, [
    HTTP_PROVIDERS,
    ROUTER_PROVIDERS,
    provide(ExceptionHandler, {useClass: ErrorHandler})
]);

为什么会出现此错误? ExceptionHandler实例化时Router不是可注入的吗?

这里有完整的源代码

https://github.com/harindaka/angular2-seed-typescript/tree/b368315ce6608085f3154a03bc53f0404ce16495

【问题讨论】:

  • 即使它没有给出错误。我认为在 angular 引发异常后它不会工作(导航)。所有角度功能都会停止。
  • @A_Singh 这是有道理的。那么在代码中出现未处理错误的情况下,使用上下文错误信息重定向到自定义错误页面的正确方法是什么?
  • 我只是显示一个带有消息的自定义警报框,然后选择重新加载应用程序,或者留下。
  • @A_Singh 嗯,我认为在这种情况下重新加载整个应用程序更有意义

标签: angular angular2-routing


【解决方案1】:

参见:ErrorHandler 类。你也可以添加Injectable装饰器来实现DI!

import { ErrorHandler, Injectable } from '@angular/core';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {

  private myService: MyService;

  constructor(private injector: Injector) {
     this.myService = injector.get(MyService);
  }

  handleError(error) {
    alert('Bad things happening');
  }
  
}

@NgModule({
  providers: [
    {
      provide: ErrorHandler, 
      useClass: GlobalErrorHandler
    }
  ]
})
export class AppModule { }

注意:以上答案使用ExceptionHandler,它在最终版本中被删除以支持ErrorHandler

【讨论】:

    【解决方案2】:

    可能迟到了,但这对我有用(Angular 2 RC4):

    import { Injectable, Injector, ExceptionHandler }    from '@angular/core';
    import { Router } from '@angular/router';
    
    @Injectable()
    export class AppExceptionHandler extends ExceptionHandler {
    
        private router;
        injector: Injector;
    
        constructor(injector: Injector) {
            super(null, null);
            this.injector = injector;
        }
    
        call(exception: any, stackTrace?: any, reason?: string): void {
            if (this.router == null) {
                this.router = this.injector.get(Router);
            }
    
            // do something with the error such as spitting out to console:
            console.log('exception:', exception);
            console.log('stackTrace:', stackTrace);
            console.log('reason:', reason);
    
            // navigate to custom error page (defined in your routes)
            this.router.navigate(['error']);
        }
    }
    

    然后在你的 main.ts 中:

    bootstrap(AppComponent, [
        HTTP_PROVIDERS,
        APP_ROUTER_PROVIDERS,
        provide(ExceptionHandler, { useClass: AppExceptionHandler })]
    )
    

    【讨论】:

      【解决方案3】:

      更新 ExceptionHandler 更名为ErrorHandler https://stackoverflow.com/a/35239028/217408

      原创

      我猜这是由循环依赖引起的。您可以通过注入注入器来解决问题并强制获取路由器:

      export class ErrorHandler extends ExceptionHandler{
      
          private router: Router 
          constructor(inject:Injector){
              this.router = injector.get(Router);
              super(null, null);
      
          }
      
          call(error, stackTrace = null, reason = null) {
              console.log(error);
              this.router.navigate(['/error']);
          }
      }
      

      【讨论】:

      • 这并没有解决。我的代码仍然出现同样的错误。
      • 我尝试使用 Plunker 进行复制,但我不知道如何摆脱 3.0.0-alpha.6 路由器。
      • 您是否将我的建议与@rinukkusu 的建议一起尝试?
      • 是的。我做到了。我在 plunkr 上遇到了和你一样的问题。您可以克隆问题中的 git repo 并尝试一下
      • 对不起,我没有在本地使用 TS(只有 Dart)。
      【解决方案4】:

      这是一个非常简单的方法——要注入到一个类中,你需要创建类injectable。听起来很熟悉,对吧?

      如果您在 ErrorHandler 类的顶部添加 @Injectable(),它应该可以工作。

      import { ExceptionHandler, Injectable } from '@angular/core';
      import { Router } from '@angular/router';
      
      @Injectable()
      export class ErrorHandler extends ExceptionHandler{
          [...]
      }
      

      【讨论】:

      • 试过了,但也没有解决错误。我不希望 ErrorHandler 类是可注入的。我需要将路由器注入到 ErrorHandler 类中。当我将 Injectable 属性添加到 ErrorHandler 类时。我得到一个不同的错误:ApplicationRef_ 实例化期间出错! (ApplicationRef -> ApplicationRef_)
      • Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'ErrorHandler' is decorated with Injectable. 听起来你不能使用@Injectable()。 :) - 可能 ApplicationRef 错误是你真正的问题。
      • Arrrgh 也许 Angular 2 超出了我的范围。你能看看github.com/harindaka/angular2-seed-typescript/tree/…
      • 运气好吗?希望你能找到一些东西。我开始相信这是设计使然,Angular 2 可能不会向异常处理程序中注入东西。
      • 遗憾的是,这似乎比我想象的要棘手 - 你可能是对的。我尽我所能,但没有办法使用注入器或注入你的ErrorHandler。 :(
      【解决方案5】:

      刚刚遇到了类似的问题并像这样解决了它(在 app 模块的 providers 数组中使用它):

      {
        provide: ExceptionHandler,
          useFactory: (router) => {
            return new ErrorHandler(router);
          },
        deps: [Router]
      }
      

      【讨论】:

      • 您使用的是哪个 RC 版本?
      • 我正在使用 Angular 2 RC 5。顺便说一句,我没有使用 Router 执行此操作,而是使用自己的自定义服务,但我希望这不会有什么不同。
      【解决方案6】:

      所以我今天遇到了类似的事情。我的情况有点不同,我扩展了需要Router的Http。但是,ErrorHandler 也需要 Http。将上面的方法与工厂一起使用,我想我可以将 Http 注入 ErrorHandler。我发现当 ErrorHandler 在 Http 的构造函数中调用依赖注入时,Router 不存在(也没有所有其他需要的上下文)。

      所以我让注入器在函数调用期间给我一个实例,而不是在构造函数中。当注入器实际尝试获取 Http(在调用中)时,它已经在适当的上下文中创建。

      CustomErrorHandler.ts:

      import { ErrorHandler, Injector } from '@angular/core';
      import { Http } from '@angular/http';
      import { environment } from 'environments/environment';
      
      export class CustomErrorHandler extends ErrorHandler {
        private http: Http;
        constructor(private injector: Injector) {
          super();
          // Calling this.injector.get(Http); here resulted in a null Router
      
          window.onerror = (msg: any, url: any, line: any, col: any, error: any) => {
            this.handleError(msg);
            return true;
          };
        }
      
        public handleError(error: any): void {
          try {
            // calling the injector here gave the application the time to build the correct context for the dependency injection that Http needed.
            if (!this.http) {
              this.http = this.injector.get(Http);
            }
            if (!error) {
              error = 'Unknown Error';
            }
            console.error(error);
            this.http.post('logtoserver/LogError', { Message: error.message, StackTrace: error.stack });
          } catch (exception) {
            // ignore
          }
        }
      }
      

      CustomHttpService.ts 中的相关部分:

      @Injectable()
      export class CustomHttpService extends Http {
      
        constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private router: Router, private injector: Injector) {
          super(backend, defaultOptions);
        }
      
        request(urlOrRequest: string | Request, options?: RequestOptionsArgs): Observable<Response> {
          // We needed Router here to call this.router.navigate(['...']);
          // ...
        }
      }
      

      app.module.ts:

      import { NgModule, ErrorHandler, Injector } from '@angular/core';
      import { Http, RequestOptions, XHRBackend } from '@angular/http';
      import { CustomErrorHandler } from 'app/customErrorHandler';
      // ...
      
      export function customHttpServiceFactory(xhrBackend, requestOptions, router, injector) {
        return new CustomHttpService(xhrBackend, requestOptions, router, injector);
      }
      
      export function customErrorHandler(injector) {
          return new CustomErrorHandler(injector);
      }
      
      @NgModule({
        declarations: [
          ...
        ],
        imports: [
          ...
        ],
        providers: [
          { provide: Http, useFactory: customHttpServiceFactory, deps: [XHRBackend, RequestOptions, Router, Injector] },
          // { provide: UrlSerializer, useClass: LowercaseUrlSerializer },
          { provide: ErrorHandler, useFactory: customErrorHandler, deps: [Injector] },
          ...
        ],
        bootstrap: [AppComponent]
      })
      export class AppModule {}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-16
        • 2016-09-02
        • 1970-01-01
        • 2017-01-01
        • 2016-12-17
        • 1970-01-01
        • 2016-12-22
        相关资源
        最近更新 更多