问题描述
我正在编写一个angular2 InterceptorModule ,它是大型核心项目的一部分.每个模块都需要完全可配置且独立.所有模块都是用 foorRoot
方法编写的,wchich允许我们实现全局单例并将任何配置传递到其中.
I am writting an angular2 InterceptorModule which is part of big core project. Every module needs to be fully configurable and independent. All modules are written with foorRoot
method wchich allow us to achieve global singletons and pass any configuration into it.
我们决定在主模块的 forRoot
方法中定义 HTTP_INTERCEPTORS
提供程序.多亏了这一点,我们在一个地方有了一种配置,所有URL规则都可以触发特定的拦截器.
We decided to define HTTP_INTERCEPTORS
providers in forRoot
metod of main module. Thanks to this we have one configuration in one place with all URL rules to fire particular interceptors.
这是主要 AppModule 的 import
部分中的简单用法:
This is simple usage in import
section of main AppModule:
CoreInterceptorModule.forRoot([
{
instance: TestInterceptor,
runConditions: [],
},
{
instance: MenuInterceptor,
runConditions: [InterceptorRunConditions.WhiteList],
whiteList: ['v1/'],
},
{
instance: MenuInterceptor,
runConditions: [
InterceptorRunConditions.WhiteList,
InterceptorRunConditions.BlackList
],
whiteList: ['v1/'],
blackList: ['v1/authorize']
},
]),
CoreStorageModule.forRoot({
mode: StorageMode.LocalStorage,
prefix: 'plCore',
modesPriority: [StorageMode.SessionStorage, StorageMode.Memory],
}),
我在将 forRoot
部分中的提供程序动态注入到 CoreInterceptorModule 的 ModuleWithProviders
中时遇到问题.
I have a problem with dynamically injecting providers from forRoot
section into ModuleWithProviders
from CoreInterceptorModule.
这是注入 HTTP_INTERCEPTORS
的有效解决方案:
This is a working solution of injecting HTTP_INTERCEPTORS
:
@NgModule({})
export class CoreInterceptorModule {
static config(interceptorConfig: IInterceptorConfig[]): ModuleWithProviders {
return {
ngModule: CoreInterceptorModule,
providers: [
{ provide: INTERCEPTOR_CONFIG, useValue: interceptorConfig },
{ provide: HTTP_INTERCEPTORS, useClass: interceptorConfig[0].instance, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: interceptorConfig[1].instance, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: interceptorConfig[2].instance, multi: true },
],
};
}
}
当然,此解决方案很糟糕,因为在 forRoot
中定义的 HTTP_INTERCEPTORS
的数量是动态的.
Of course this solution is bad because amount of HTTP_INTERCEPTORS
defined in forRoot
is dynamic.
解决方案只是动态注入提供者,就像这样:
Solution is just to inject providers dynamically, like that:
@NgModule({})
export class CwaCoreInterceptorModule {
static forRoot(interceptorConfig: IInterceptorConfig[]): ModuleWithProviders {
// base module configuration
const moduleWithProviders: ModuleWithProviders = {
ngModule: CwaCoreInterceptorModule,
providers: [
{ provide: INTERCEPTOR_CONFIG, useValue: interceptorConfig },
],
};
// update HTTP_INTERCEPTORS array
interceptorConfig.forEach((e) => {
moduleWithProviders.providers.push({
provide: HTTP_INTERCEPTORS, useClass: e.instance, multi: true
});
});
return moduleWithProviders;
}
}
这段导致异常的代码:
模板"AppModule"的编译过程中发生错误装饰器不支持函数调用,但支持'CoreInterceptorModule'被呼叫.
我阅读了一些有关此问题的主题,但对我而言,这些主题都无济于事.问题在于,无法在 forRoot
方法中的 return
语句之前调用任何函数.
I read some topics about this problem and none of them helped in my case. The problem is that it's not possible to call any function before return
statement in forRoot
method.
问题是如何在 forRoot
方法中动态添加 HTTP_INTERCEPTORS
?我想到了类似 useFactory
的东西,但它似乎只能返回一个值(一个实例).
The question is how dynamically add HTTP_INTERCEPTORS
in forRoot
method? I thought about something like useFactory
but it seams it can return just one value (one instance).
推荐答案
我解决了这个问题.我没有使用我的自定义配置类型 IInterceptorConfig
(以后无法迭代),而是创建了从原始 Angular \ @code \ classProvider
继承的自定义Angular DI提供程序类型:
I resolved this problem. Instead of using my custom configuration type IInterceptorConfig
(which is later impossible to iterate) I created custom Angular DI provider type inherited from original Angular\@code\classProvider
:
export interface InterceptorClassProvider extends ClassProvider {
runConditions: InterceptConditions[];
whiteList?: string[];
blackList?: string[];
}
感谢此我还有其他字段. forRoot
方法配置如下:
Thanks to this I have my additional fields. forRoot
method configuration looks like that:
CwaCoreInterceptorModule.forRoot([
{
provide: HTTP_INTERCEPTORS,
useClass: MenuInterceptor,
multi: true,
runConditions: [InterceptConditions.WhiteList],
whiteList: ['/v1']
},
]),
最后,最重要的一点是,我可以动态地在sharedModule中填充 ModuleWithProviders
接口:
And finally and the most important I can dynamically fill ModuleWithProviders
interface in sharedModule without errors:
static forRoot(interceptorProviders: InterceptorClassProvider[]): ModuleWithProviders {
return {
ngModule: CwaCoreInterceptorModule,
providers: [
{ provide: INTERCEPTOR_CONFIG, useValue: interceptorProviders },
...interceptorProviders
],
};
}
它之所以有效,是因为我使用了数组扩展运算符( ...
)而不是任何其他函数调用.此解决方案的唯一弊端是一些不必要的属性,例如 provide
, useClass
, multi
,这些属性不能封装在任何较低的层中.
It works because I use array spread operator (...
) instead of any additional functions call. The only cons of this solution is some unnecessary attributes like provide
, useClass
, multi
which can not be encapsulated in any lower layer.
这篇关于具有forRoot的动态提供程序数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!