Angular 2:如何在创建之前传递服务配置?
问题描述:
我有一个典型的用例,我必须使用不同的端点websocket URL来连接不同的后端服务。Angular 2:如何在创建之前传递服务配置?
我已经写了通用的服务在角2见下图:
import {Injectable} from "@angular/core";
import {Subject} from "rxjs/subject";
import {Observable} from "rxjs/observable";
import {WebSocketSubject, WebSocketSubjectConfig} from "rxjs/observable/dom/WebSocketSubject";
import {Observer} from "rxjs/observer";
@Injectable()
export class WebSocketService<T> extends Subject<T> {
private reconnectionObservable: Observable<number>;
private wsSubjectConfig: WebSocketSubjectConfig;
private socket: WebSocketSubject<any>;
private connectionObserver: Observer<boolean>;
public connectionStatus: Observable<boolean>;
constructor(private config: WebServiceConfig) {
super();
// connection status
this.connectionStatus = new Observable((observer) => {
this.connectionObserver = observer;
}).share().distinctUntilChanged();
// config for WebSocketSubject
// except the url, here is closeObserver and openObserver to update connection status
this.wsSubjectConfig = {
url: config.URL,
closeObserver: {
next: (e:CloseEvent) => {
this.socket = null;
this.connectionObserver.next(false);
}
},
openObserver: {
next: (e:Event) => {
this.connectionObserver.next(true);
}
}
};
this.connect();
// we follow the connection status and run the reconnect while losing the connection
this.connectionStatus.subscribe((isConnected) => {
if (!this.reconnectionObservable && typeof(isConnected) == "boolean" && !isConnected) {
this.reconnect();
}
});
}
connect():void {
this.socket = new WebSocketSubject(this.wsSubjectConfig);
this.socket.subscribe(
(m) => {
this.next(m); // when receiving a message, we just send it to our Subject
},
(error:Event) => {
if (!this.socket) {
// in case of an error with a loss of connection, we restore it
this.reconnect();
}
});
}
reconnect():void {
this.reconnectionObservable = Observable.interval(this.config.getRetryInterval())
.takeWhile((v, index) => {
return index < this.config.attempts && !this.socket
});
this.reconnectionObservable.subscribe(
() => {
this.connect();
},
null,
() => {
// if the reconnection attempts are failed, then we call complete of our Subject and status
this.reconnectionObservable = null;
if (!this.socket) {
this.complete();
this.connectionObserver.complete();
}
});
}
send(data:any):void {
this.socket.next(this.config.serializer(data));
}
}
export enum TimeUnits {
SECONDS = 1000,
MINUTES = SECONDS * 60,
HOURS = MINUTES * 60,
DAYS = HOURS * 24
}
export class WebServiceConfig {
URL: string = 'ws://localhost:4242/ws';
attempts: number = 10; /// number of connection attempts
retryUnit: TimeUnits = TimeUnits.SECONDS; /// pause between connections
retryInterval: number = 5;
serializer: (data: any) => any = function (data: any) {
return JSON.stringify(data);
};
deserializer: (e: MessageEvent) => any = function (e: MessageEvent) {
return e;
};
getRetryInterval(): number {
return this.retryUnit * this.retryInterval;
};
}
现在的问题是如何创建具有不同配置的新实例?
我认为的一种方法是扩展到子类并通过配置。有更好的方法来创建扩展类吗?
配置是动态的!我的意思是它将写入服务器端的页面(我们使用后端的句柄来渲染模板)。
答
有几个方法可以做到你想要什么:
export class SampleConfig {
constructor(public value:string)
{
}
}
@Injectable()
export class SampleService {
constructor(config:SampleConfig)
{
console.debug('config', config);
}
}
providers : [
...
{provide: SampleService, useFactory:() => new SampleService(new SampleConfig('1'))},
...
],
providers : [
...
{provide: SampleConfig, useValue: new SampleConfig('1')},
SampleService,
...
],
答
我在我的应用程序中有类似的要求,只是使用基本服务,完美的作品。你有什么反对继承配置对象?下面是我怎么有我的设置柜面它的方便的例子...
export class BaseService {
protected options: { ... };
constructor(...) { }
init(options) {
this.options = options;
...
}
然后,你需要可以只是建立你的选择任何子类对象,然后调用初始化它们。这样,您只需编写一次所有方法的抽象版本。我的基地服务非常丰富,但所有的儿童课程都非常简洁。
+0
太多的代码和测试)... – user3130446
谢谢你,我已经实现了这个解决方案,这一方式允许隔离(限制范围)到模块或组件。 – user3130446