使用 Angular 重新连接到现有的 SignalR (.NET CORE) 套接字
Reconnecting to an existing SignalR (.NET CORE) socket with Angular
在我的项目中,如果 Internet 连接丢失,我需要重新连接到 SignalR Web Socket。
我正在使用 Angular Ionic V4,并且安装了网络信息插件。
在插件的 "Connected" 事件中 - 我正在尝试使用原始令牌调用 this._hubConnection.start()
。似乎建立了新连接,但每次我从集线器获取数据时,事件都会运行两次(或 X 次,具体取决于我重新连接的次数)。
我相信发生的事情是 SignalR 在同一个密钥下创建另一个套接字,并且当消息发送到指定的密钥时 - 它被广播到具有相同密钥的所有连接,因此重复事件。
我的问题是 - 有没有办法 "reconnect" 到现有套接字而不是 "making an additional connection"?
编辑:
尝试升级到@microsoft/signalr后,我得到的是:
chrome devtool console log
它似乎在网络离线时尝试重新连接,当网络恢复时它连接并断开连接。
我尝试调试我的 SignalR 服务器。这是在客户端调用事件的方法:
public async Task Enqueue(int processId)
{
var processEnqueueAppointmentResults = await _processesService.Enqueue<object>(processId);
await Clients.User($"PROCESS_{processId}").SendAsync("ProcessEnqueued", processEnqueueAppointmentResults);
}
调试器进入 Enqueue 一次,在客户端 - 我收到了 4 个重复的日志(意味着事件被触发了 4 次)
由于您使用的是旧的且未维护的 @aspnet/signalr
包,我建议切换到提供 Automatic Reconnect
功能的新包 @microsof/singnalR
。
因此,您可以使用此功能让 SignalR 在不是错误的情况下处理丢失的连接,就像您示例断开的互联网连接一样。
您只需像这样添加此功能:
this.hubMessageConnection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Error).withUrl(signalRUrl + "/yourHub",
{
accessTokenFactory: () => token
})
.withAutomaticReconnect()
.build();
这证明可以解决您的问题。
已解决
问题是在我的 Internet 连接事件中,我调用了 createConnection()
初始化 SignalR 连接的方法
this._hubConnection = new signalR.HubConnectionBuilder()
.withUrl(`${this.env.testUrl}/hubs/patients`, {
accessTokenFactory: () => token
})
.build();
相反,只需在我现有的 hubConnection 上调用 this._hubConnection.start();
方法即可解决重复调用(正如我所想,每个重新连接事件都在同一键下添加了另一个套接字。当 SignalR 想要调用客户端上的事件 - 它触发了我调用的次数 createConnection()
)
我一起编写了一个“安全调用约定”——仍然需要更通用,但想法是你在集线器上调用一个方法——如果连接断开,那么连接应该恢复并再次调用该方法。如果连接断开,并且不会恢复,请继续重新绑定,直到连接恢复,然后在打开的连接上调用该方法。
getChatSubjects(subject?: Subject<ChatSubject[]>) {
if(!subject) {
subject = new Subject<ChatSubject[]>();
}
let connectionState = (this.connection as any)._connectionState;
console.log("connection state " + connectionState);
if( connectionState == "Connected" ) {
this.connection.invoke("GetChatSubjects").then(results => {
this.chatSubjects = [];
for (var i = 0; i < results.length; i++) {
this.chatSubjects.push(results[i]);
}
subject.next(this.chatSubjects);
});
}
else if(connectionState == "Reconnecting") {
let message = "Connection in reconnecting state, retrying in 3 seconds";
console.log(message)
timer(3000).pipe(take(1)).subscribe(time => this.getChatSubjects(subject));
}
else {
console.log("connection in a closed state")
console.log("trying to open connection again")
this.startConnecton().then(result => {
if(!result) {
console.log("could no re-open connection");
console.log("will retry in 10 seconds");
timer(10000).pipe(take(1)).subscribe(time => this.getChatSubjects(subject));
}
else {
console.log("connection re-opened")
timer(1000).pipe(take(1)).subscribe(time => this.getChatSubjects(subject));
}
})
}
}
...
let subject = new Subject<ChatSubject[]>();
subject.subscribe(results => {
this.chatSubjects = results;
})
this.signalRService.getChatSubjects(subject)
注意源代码使用 RXJS。另请注意,我选择不在 signalR 连接上使用自动重新连接功能,因为它太“快乐”了,但仍然允许您在关闭的连接上调用方法。
在我的项目中,如果 Internet 连接丢失,我需要重新连接到 SignalR Web Socket。
我正在使用 Angular Ionic V4,并且安装了网络信息插件。
在插件的 "Connected" 事件中 - 我正在尝试使用原始令牌调用 this._hubConnection.start()
。似乎建立了新连接,但每次我从集线器获取数据时,事件都会运行两次(或 X 次,具体取决于我重新连接的次数)。
我相信发生的事情是 SignalR 在同一个密钥下创建另一个套接字,并且当消息发送到指定的密钥时 - 它被广播到具有相同密钥的所有连接,因此重复事件。
我的问题是 - 有没有办法 "reconnect" 到现有套接字而不是 "making an additional connection"?
编辑:
尝试升级到@microsoft/signalr后,我得到的是:
chrome devtool console log
它似乎在网络离线时尝试重新连接,当网络恢复时它连接并断开连接。
我尝试调试我的 SignalR 服务器。这是在客户端调用事件的方法:
public async Task Enqueue(int processId)
{
var processEnqueueAppointmentResults = await _processesService.Enqueue<object>(processId);
await Clients.User($"PROCESS_{processId}").SendAsync("ProcessEnqueued", processEnqueueAppointmentResults);
}
调试器进入 Enqueue 一次,在客户端 - 我收到了 4 个重复的日志(意味着事件被触发了 4 次)
由于您使用的是旧的且未维护的 @aspnet/signalr
包,我建议切换到提供 Automatic Reconnect
功能的新包 @microsof/singnalR
。
因此,您可以使用此功能让 SignalR 在不是错误的情况下处理丢失的连接,就像您示例断开的互联网连接一样。
您只需像这样添加此功能:
this.hubMessageConnection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Error).withUrl(signalRUrl + "/yourHub",
{
accessTokenFactory: () => token
})
.withAutomaticReconnect()
.build();
这证明可以解决您的问题。
已解决
问题是在我的 Internet 连接事件中,我调用了 createConnection()
初始化 SignalR 连接的方法
this._hubConnection = new signalR.HubConnectionBuilder()
.withUrl(`${this.env.testUrl}/hubs/patients`, {
accessTokenFactory: () => token
})
.build();
相反,只需在我现有的 hubConnection 上调用 this._hubConnection.start();
方法即可解决重复调用(正如我所想,每个重新连接事件都在同一键下添加了另一个套接字。当 SignalR 想要调用客户端上的事件 - 它触发了我调用的次数 createConnection()
)
我一起编写了一个“安全调用约定”——仍然需要更通用,但想法是你在集线器上调用一个方法——如果连接断开,那么连接应该恢复并再次调用该方法。如果连接断开,并且不会恢复,请继续重新绑定,直到连接恢复,然后在打开的连接上调用该方法。
getChatSubjects(subject?: Subject<ChatSubject[]>) {
if(!subject) {
subject = new Subject<ChatSubject[]>();
}
let connectionState = (this.connection as any)._connectionState;
console.log("connection state " + connectionState);
if( connectionState == "Connected" ) {
this.connection.invoke("GetChatSubjects").then(results => {
this.chatSubjects = [];
for (var i = 0; i < results.length; i++) {
this.chatSubjects.push(results[i]);
}
subject.next(this.chatSubjects);
});
}
else if(connectionState == "Reconnecting") {
let message = "Connection in reconnecting state, retrying in 3 seconds";
console.log(message)
timer(3000).pipe(take(1)).subscribe(time => this.getChatSubjects(subject));
}
else {
console.log("connection in a closed state")
console.log("trying to open connection again")
this.startConnecton().then(result => {
if(!result) {
console.log("could no re-open connection");
console.log("will retry in 10 seconds");
timer(10000).pipe(take(1)).subscribe(time => this.getChatSubjects(subject));
}
else {
console.log("connection re-opened")
timer(1000).pipe(take(1)).subscribe(time => this.getChatSubjects(subject));
}
})
}
}
...
let subject = new Subject<ChatSubject[]>();
subject.subscribe(results => {
this.chatSubjects = results;
})
this.signalRService.getChatSubjects(subject)
注意源代码使用 RXJS。另请注意,我选择不在 signalR 连接上使用自动重新连接功能,因为它太“快乐”了,但仍然允许您在关闭的连接上调用方法。