dependency-injection - 如何在 Angular2 中正确使用依赖注入(inject)?

标签 dependency-injection angular

我在解决 DI 问题方面取得了不同程度的成功。我已经阅读了一些教程并且掌握了要点,但是在使用我的自定义服务制作了一些嵌套的 DI 之后,事情开始分崩离析。

有人可以解释一下何时使用 useFactory 而不是 useClass 吗?我看过 ng2 文档和示例,但我无法将它们映射到我的问题。目前我的 Bootstrap 看起来像这样:

bootstrap(
    App,
    [
        FORM_PROVIDERS,
        ROUTER_PROVIDERS,
        HTTP_PROVIDERS,
        provide(LocationStrategy, { useClass: PathLocationStrategy }),
        provide(RequestOptions, { useClass: DefaultRequestOptions }),
        provide(MsgService, { useClass: MsgService }),
        provide(HttpAdvanced, { useFactory: (MsgService, HTTP_PROVIDERS) => new HttpAdvanced(MsgService, HTTP_PROVIDERS), deps: [MsgService, HTTP_PROVIDERS] }),
        provide(AuthService, { useFactory: (HttpAdvanced) => new AuthService(HttpAdvanced), deps: [HttpAdvanced, HTTP_PROVIDERS, MsgService] }),
        provide(FormBuilderAdvanced, { useFactory: (FormBuilder, HttpAdvanced) => new FormBuilderAdvanced(FormBuilder, HttpAdvanced), deps: [FormBuilder, HttpAdvanced] }),
        provide(MsgServiceInternal, { useClass: MsgServiceInternal })
    ]
);

我的最新一期是:

EXCEPTION: Error during instantiation of AuthService! (HeaderBar -> AuthService).
ORIGINAL EXCEPTION: TypeError: this.http.get is not a function

我的依赖是这样的

HttpAdvanced        -> Http(ng2), MsgService
MsgService          -> MsgServiceInternal
AuthService         -> HttpAdvanced
FormBuilderAdvanced -> FormBuilder(ng2), HttpAdvanced

1. 我是否正确使用了 provide/useClass/useFactory 以及如何提供具有其他依赖项的服务?

此外,我的代码中有一处:

static isUserInjector() {
    return (next, prev) => Injector.resolveAndCreate([AuthService, provide(HttpAdvanced, { useClass: HttpAdvanced })]).get(AuthService).isUser();
}

因为我想有一个功能,我提供给

@CanActivate(AuthService.isEditorInjector())

但是我不能使用构造函数注入(inject),因为@CanActivate 在类范围之外,所以我不能在 Controller 中注入(inject)服务,然后像 @CanActivate(this.authService.isEditor())

2.对此有什么好的解决方案?

一些代码:

@Component({
    selector: 'ShowStats',
    templateUrl: './dest/views/showStats/showStats.html',
    directives: [ COMMON_DIRECTIVES, UsersCount, AdminsList, GlobalWishlist, PopularTrack ]
})
export class ShowStats {
    authService : AuthService;

    constructor( authService : AuthService ){
        this.authService = authService;
    }
}

... next file ...

@Injectable()
export class HttpAdvanced {
    msgService: MsgService;
    http: Http;

    constructor(msgService: MsgService, http: Http) {
        this.msgService = msgService;
        this.http = http;
    }

    /*
     * This is for plain ol' GET requests .. with callback of course.
     */
    public get(url, callback) {
        return this.http.get(url).subscribe((res) => {
            let data = res.json().data;
            callback(data);
        }, this.msgService.httpErrorHandler);
    }
.... other code for HttpAdvanced

3. 导入文件的顺序对 DI 有影响吗?我想我注意到,因为我在同一个文件中有 MsgService 和 MsgServiceInternal,而 MsgService 依赖于 Internal,我之前必须把 Internal 但我不是 100% importing 的顺序相同吗?

4. 所以如果我只是这样做:

bootstrap(
    App,
    [
        FORM_PROVIDERS,
        ROUTER_PROVIDERS,
        HTTP_PROVIDERS,
        provide(LocationStrategy, { useClass: PathLocationStrategy }),
        provide(RequestOptions, { useClass: DefaultRequestOptions }),
        MsgService,
        HttpAdvanced,
        AuthService,
        FormBuilderAdvanced,
        MsgServiceInternal
    ]
);

我得到:

Cannot resolve all parameters for 'FormBuilderAdvanced'(?, ?). 
Make sure that all the parameters are decorated with Inject or have 
valid type annotations and that 'FormBuilderAdvanced' is decorated 
with Injectable.

我过去常常使用 useFactory 来消除这个错误,但现在我很困惑。这是否意味着 deps 没有被注入(inject)是因为它看不到它们还是什么?

表单类:

export class FormBuilderAdvanced {
    http: HttpAdvanced;
    fb: FormBuilder;

    constructor(fb: FormBuilder, http: HttpAdvanced) {
        this.fb = fb;
        this.http = http;
    }

    create(controlNames: string[], submissionUrl: string, getter?: any) {
        return new Form(this.fb, this.http, controlNames, submissionUrl, getter);
    }
}

最佳答案

你的问题没有提供足够的信息来确定,但这可能就足够了

bootstrap(
    App,
    [
        FORM_PROVIDERS,
        ROUTER_PROVIDERS,
        HTTP_PROVIDERS,
        provide(LocationStrategy, { useClass: PathLocationStrategy }),
        provide(RequestOptions, { useClass: DefaultRequestOptions }),
        // provide(MsgService, { useClass: MsgService }),
        MsgService, // is just fine when no special behavior is required
        // provide(HttpAdvanced, { useFactory: (MsgService, HTTP_PROVIDERS) => new HttpAdvanced(MsgService, HTTP_PROVIDERS), deps: [MsgService, HTTP_PROVIDERS] }),
        provide(Http, {useClass: HttpAdvanced});
        AuthService,
        provide(FormBuilder, { useClass: FormBuilderAdvanced}),
        MsgServiceInternal)
    ]
);

如果你想让一个类可用于注入(inject),只需将类型添加到提供者列表(provide(AuthService) 和只是 AuthService 做同样的事情)。 如果您想注入(inject)一个与请求的类不同的类,请使用 useClass

例子

@Injectable()
export class MyService {
  constructor(private http: Http) {
  }
}

如果您的提供者包含

provide(Http, {useClass: HttpAdvanced});

然后 MyService(依赖于 Http)被注入(inject) HttpAdvanced。 确保在 HTTP_PROVIDERS 之后有此行以覆盖 HTTP_PROVIDERS 中包含的默认 Http 提供程序。

如果 DI 无法自行解决依赖关系,因为它们不仅仅是其他提供者,则使用 useFactory

如上所述,

Ensure you have this line after HTTP_PROVIDERS to override the default Http provider, contained in HTTP_PROVIDERS.

提供者列表中的顺序很重要。 当提供者列表包含一个类型的多个提供者时,则只使用最后一个。

导入 的顺序无关紧要。

一个文件中依赖类的顺序确实很重要,因为类没有提升。

例子

export class ClassA {
   // constructor(private b: ClassB) {} // ClassB is unknown here
   constructor(@Inject(forwardRef(() => DataService)) {
   }
}

export class ClassB {
}

如果ClassB的代码在ClassA之上,则不需要forwardRef()

另见 Class is not injectable if it is defined right after a component with meta annotation

关于dependency-injection - 如何在 Angular2 中正确使用依赖注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34943589/

相关文章:

java - CDI bean 的 Servlet 和范围

scala - 如何使用 Play 2.4 将服务注入(inject)到 Actor 中?

Angular Nginx Docker 404

angular - 如果未找到图像源,则显示列表中项目的前两个字母

java - play 2.5 生产模式无法在应用程序启动时运行的 Singleton 类中使用注入(inject)的 ConfigurationProvider 类对象

c# - Unity Bootstrapper (Unity.Mvc), Unity 3, MVC 5, EF6 接收错误 : Parameterless Public Constructor on Controller

javascript - 替换 html 后重启 Angular 应用程序

angular 5删除组件销毁上的样式节点

dependency-injection - 在 UnityContainer 中注册 NUnit DynamicMock 实例

angular - 预计 observable 在 Angular/Karma/Jasmine 测试中失败