【问题标题】:Reconnecting to an existing SignalR (.NET CORE) socket with Angular使用 Angular 重新连接到现有的 SignalR (.NET CORE) 套接字
【发布时间】:2020-09-23 11:17:42
【问题描述】:

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

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

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

编辑:

在尝试升级到@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 次)

【问题讨论】:

  • 你用什么角度包来signalR?
  • @aspnet/signalr

标签: angular ionic-framework .net-core websocket signalr


【解决方案1】:

由于您使用的是旧的且未维护的 @aspnet/signalr 软件包,我建议您切换到提供 Automatic Reconnect 功能的新软件包 @microsof/singnalR

因此,您可以使用此功能让 SignalR 在没有错误时处理丢失的连接,就像您举例的互联网连接断开一样。

你只需像这样添加这个功能:

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

这可能会纠正您的问题。

【讨论】:

  • 我尝试安装新包而不是旧包。它似乎确实尝试重新连接,但没有成功。当我的网络出现故障时,它尝试以 3 秒的时间间隔 (orso) 重新连接。我恢复了网络,它已连接,但立即断开连接(没有尝试重新连接)
  • @YoniZiv 你好。也许您应该尝试更大的间隔,例如 3、5、10、15 秒?
  • @YoniZiv 如果你愿意,我可以为你提供一个我如何处理前端连接的例子......
【解决方案2】:

解决了

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

this._hubConnection = new signalR.HubConnectionBuilder()
      .withUrl(`${this.env.testUrl}/hubs/patients`, {
        accessTokenFactory: () => token
      })
      .build();

相反,只需要在我现有的 hubConnection 上调用 this._hubConnection.start(); 方法即可解决重复调用(就像我想的那样,每个重新连接事件都会在同一个键下添加另一个套接字。当 SignalR 想要在客户端调用事件时- 它触发了我调用 createConnection()) 的次数

【讨论】:

  • 您从哪里获得token 的值?
【解决方案3】:

我编写了一个“安全调用约定”——仍然需要更通用,但想法是你在集线器上调用一个方法——如果连接断开,那么应该重新建立连接并且方法再次调用。如果连接断开,并且不会恢复,请继续重试,直到连接恢复,然后在打开的连接上调用该方法。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-17
    • 2021-01-09
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多