使用 Angular 重新连接到现有的 SignalR (.NET CORE) 套接字



在我的项目中,如果互联网连接丢失,我需要重新连接到 SignalR Web Socket。 我正在使用Angular Ionic V4,并安装了网络信息插件。 在插件的"已连接"事件上 - 我正在尝试使用原始令牌调用this._hubConnection.start()。似乎建立了新连接,但每次我从中心获取数据时,事件都会运行两次(或 X 次,具体取决于我建立了多少次重新连接(。

我相信正在发生的事情是 SignalR 在同一键下创建另一个套接字,当消息发送到指定的键时 - 它被广播到具有相同键的所有连接,从而复制事件。

我的问题是 - 有没有办法"重新连接"到现有套接字而不是"建立额外的连接"?

编辑:

尝试升级到@microsoft/信号器后,这就是我得到的:

Chrome 开发工具控制台日志

它似乎在网络脱机时尝试重新连接,当网络恢复时,它会连接和断开连接。

我尝试调试我的 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

因此,可以使用此功能在丢失的连接不是错误时处理丢失的连接,就像示例断开的互联网连接一样。

您只需添加此功能,例如:

this.hubMessageConnection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Error).withUrl(signalRUrl + "/yourHub",
{
accessTokenFactory: () => token
})
.withAutomaticReconnect()
.build();

这可以证明可以纠正您的问题。

已解决

问题是在我的互联网连接事件中,我调用了初始化 SignalR 连接的createConnection()方法

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 连接上使用自动重新连接功能,因为它太"快乐的日子",并且仍然允许您在关闭的连接上调用方法。

最新更新