.NET Core SignalR,服务器超时/重新连接问题

时间:2018-07-05 06:23:22

标签: .net-core asp.net-core-mvc signalr

我有一个用我的MVC解决方案编写的SignalR集线器,并且有一个Javascript客户端从视图连接。

连接点是从服务器接收墙板的更改。这几乎必须立即发生,并且需要终身连接,因为该网页在没有直接访问PC的屏幕上运行。

到目前为止,SignalR连接工作了几个小时才给出错误。

我得到的错误是

Error: Connection disconnected with error 'Error: Server timeout elapsed without receiving a message form the server.'.
Failed to load resource: net::ERR_CONNECTION_TIMED_OUT
Warning: Error from HTTP request. 0:
Error: Failed to complete negotiation with the server: Error
Error: Failed to start the connection: Error

Uncaught (in promise) Error
    at new HttpError (singlar.js:1436)
    at XMLHttpRequest.xhr.onerror (singalr.js:1583)

我的客户代码

 let connection = new signalR.HubConnectionBuilder()
    .withUrl("/wbHub")
    .configureLogging(signalR.LogLevel.Information)
    .build();

connection.start().then(function () {
    connection.invoke("GetAllWallboards").then(function (wallboard) {
        for (var i = 0; i < wallboard.length; i++) {
            displayWallboard(wallboard[i]);
        }
        startStreaming();
    })
})

connection.onclose(function () {
    connection.start().then(function () {
            startStreaming();
    })
})

function startStreaming() {
    connection.stream("StreamWallboards").subscribe({
        close: false,
        next: displayWallboard
    });
}

集线器代码

public class WallboardHub : Hub
{
    private readonly WallboardTicker _WallboardTicker;

    public WallboardHub(WallboardTicker wallboardTicker)
    {
        _WallboardTicker = wallboardTicker;
    }

    public IEnumerable<Wallboard> GetAllWallboards()
    {
        return _WallboardTicker.GetAllWallboards();
    }

    public ChannelReader<Wallboard> StreamWallboards()
    {
        return _WallboardTicker.StreamWallboards().AsChannelReader(10);
    }

    public override async Task OnConnectedAsync()
    {
        await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception exception)
    {
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users");
        await base.OnDisconnectedAsync(exception);
    }
}

问题1:我处理重新连接的方式是否正确?从错误中可以感觉到.onclose可以正常工作,但是只能尝试一次?无论如何,在显示错误之前要尝试x分钟?

问题2:重新加载网站可使连接重新工作,是否有可能在signalR连接错误时刷新浏览器?

3 个答案:

答案 0 :(得分:4)

我遇到了同样的问题(问题1),我对此进行了解决:

const connection = new SignalR.HubConnectionBuilder()
    .withUrl("/hub")
    .configureLogging(SignalR.LogLevel.Information)
    .build();

connect(connection);

async function connect(conn){
    conn.start().catch( e => {
        sleep(5000);
        console.log("Reconnecting Socket");
        connect(conn);  
    }
    )
}

connection.onclose(function (e) {
            connect(connection);
    });

  async function sleep(msec) {
  return new Promise(resolve => setTimeout(resolve, msec));
}

每5秒钟尝试重新连接一次,但我不知道这是否是正确的方法。

答案 1 :(得分:2)

带有相应SignalR版本的ASP.NET Core 2.1(当前LTS版本)似乎没有可用的某些集成的重新连接方法。 @Shidarg中的代码对我不起作用,它在浏览器崩溃的无限循环中调用reconnect方法。我也更喜欢C#中的async / await语法,所以我更新了它:

let reconnectWaitTime = 5000
let paramStr = '?myCustomArg=true'
let client = new signalR.HubConnectionBuilder()
    .withUrl("/overviewHub" + paramStr)
    .build();

client.onclose(async () => {
    console.warn(`WS connection closed, try reconnecting with loop interval ${reconnectWaitTime}`)
    tryReconnect(client)
})
await tryReconnect(client)

async function tryReconnect(client) {
    try {
        let started = await client.start()
        console.log('WS client connected!')

        // Here i'm initializing my services, e.g. fetch history of a chat when connection got established

        return started;
    } catch (e) {
        await new Promise(resolve => setTimeout(resolve, reconnectWaitTime));
        return await tryReconnect(client)
    }
}

但是对于ASP.NET Core 3,它们包括一种重新连接方法:

let client = new signalR.HubConnectionBuilder()
    .withUrl("/myHub")
    .withAutomaticReconnect()
    .configureLogging(signalR.LogLevel.Information)
    .build();

默认情况下,它尝试三次重新连接:第一次在2秒后,第二次在10秒后,最后大约30秒。可以通过将intervalls作为数组参数来进行修改:

.withAutomaticReconnect([5000, 1500, 50000, null])

此示例在5s,15s和50s之后重试。最后一个null参数告诉SignalR停止重试。在此处可以找到更多信息:https://www.jerriepelser.com/blog/automatic-reconnects-signalr/

答案 2 :(得分:1)

配置自动重新连接只需要在HubConnectionBuilder上调用withAutomaticReconnect。这是配置连接的我的JavaScript代码的样子:

connection = new signalR.HubConnectionBuilder()
.withUrl("/publish-document-job-progress")
.withAutomaticReconnect()
.configureLogging(signalR.LogLevel.Information)
.build();

您可以通过将重试延迟数组传递给withAutomaticReconnect()来配置退避时间。缺省值为[0,2000,10000,30000,null]。空值告诉SignalR停止尝试。因此,例如,如果我希望它在0、1秒和5秒后重试,则可以如下配置我的HubConnectionBuilder:

connection = new signalR.HubConnectionBuilder()
.withUrl("/publish-document-job-progress")
.withAutomaticReconnect([0, 1000, 5000, null])
.configureLogging(signalR.LogLevel.Information)
.build();