在Aurelia中,我有几个依赖于相同配置的类。使用 IoC/DI,此配置可以作为构造函数参数提供似乎是很自然的。例如:
@autoinject
export class CustomerService {
constructor(config: IRemoteServiceConfig) {
}
}
@autoinject
export class GummyBearService {
constructor(config: IRemoteServiceConfig) {
}
}
在最简单的示例中,IRemoteServiceConfig可能看起来像这样(为简洁起见,删除了其他内容(:
export IRemoteServiceConfig {
endpoint: string;
apiKey?: string;
// etc. several other settings
}
将配置注入构造函数非常适合测试,并且不需要我读取每个类中的配置和设置。
这些服务依赖于相同的配置,我想在我的应用程序中定义一次 - 在启动期间 - 定义一次。
通读有关依赖注入的Aurelia文档,我看到有几种方法可用于此目的,例如registerInstance()
,registerResolver()
和registerSingleton()
。文档确实缺乏一些关于如何以及在何处定义这一点的上下文。
我从启动例程的configure()
部分中的以下内容开始:
// register a static config; for brevity these are hardcoded settings
// but could come from anywhere
container.registerSingleton(IRemoteServiceConfig, () => {
return <IRemoteServiceConfig> {
endpoint: 'http://foo.com/api/v23/',
apiKey: 'abc'
}
});
它似乎没有拾取任何东西(没有错误(。但这也可能只是我对如何初始化容器的无知。
我的问题:我如何以及在哪里可以在Aurelia中定义IRemoteServiceConfig(如果有的话(,以便一旦DI启动服务,它就会自动拾取我的(硬编码(配置?
请注意,在这个SO问题中提到"它不能与接口一起使用,因为TypeScript在运行时编译了这些接口。这个问题也是+2年前的,无论是在Aurelia还是在TypeScript中,都发生了很大的变化。无论情况是否仍然如此,同样的问题也适用于类的实例而不是接口。
另请注意,我知道诸如aurelia-configuration之类的库,它们似乎适合将应用程序设置存储在配置文件中(并且工作正常(。这对于给出的例子更有意义。但是这个问题纯粹与如何定义要由Aurelia DI解析的类的接口或特定实例有关。
> @estus提供的答案是正确的,我已将其标记为答案。虽然,我确实遇到了一些额外的问题来使其正常工作。为了指出这一点,我花时间在下面写了一个带有更多详细信息的答案,希望将来可以帮助其他人。
1.( 使用类,而不是接口 就像接受的答案状态一样,您不能使用接口
- 它必须是一个类。
2.(通过 aurelia.container 访问全局容器实例
文档没有提到如何获取容器的实例。但是你可以通过aurelia.container
直接调用configure()
操作中的默认/全局容器,如下所示:
aurelia.container.registerSingleton(RemoteServiceConfig, () => {
var config = new RemoteServiceConfig();
config.endpoint = 'http://foo.com/api/v23/',
config.apiKey = 'abc'
});
我犯了初始化 Container(( 的新实例的错误,并尝试以某种方式在 configure(( 操作中注入它。我不应该有:)
3.(将类拆分到不同的文件中 这看起来很愚蠢,但很重要:这些类不能位于同一个文件中
,否则您将收到以下错误:
键/值不能为 null 或未定义。您是否正在尝试注入/注册 DI 不存在的内容?
出于原始问题的目的,我在同一个 app.ts 文件中创建了所有类。这似乎根本行不通。
话虽如此,完整的应用程序现在看起来像这样并且可以工作:
主目录
import { Aurelia } from 'aurelia-framework'
import { RemoteServiceConfig } from './app';
export function configure(aurelia: Aurelia) {
aurelia.use
.standardConfiguration()
.feature('resources');
aurelia.container.registerSingleton(RemoteServiceConfig, () => {
var config = new RemoteServiceConfig();
config.endpoint = 'http://foo.com/api/v23/',
config.apiKey = 'abc'
});
aurelia.start().then(() => aurelia.setRoot());
}
应用程序
import { autoinject } from 'aurelia-dependency-injection';
// note: classes below should be 3 different files!
@autoinject
export class App {
constructor(private service: CustomerService) {
}
}
@autoinject
export class CustomerService {
constructor(private config: RemoteServiceConfig) {
}
}
export class RemoteServiceConfig {
public endpoint: string;
public apiKey?: string;
}
无论使用哪个 TypeScript 版本,接口在运行时都不存在。
为了同时用作接口和 DI 令牌,IRemoteServiceConfig
应该是一个类:
export abstract class IRemoteServiceConfig { ... }