signalR tracking connected users

2019-03-29 13:29发布

问题:

I need to check whether a specific user is still connected.

I have the following HashSet that keeps track of users:

public static class UserHandler
{
    public static HashSet<string> ConnectedIds = new HashSet<string>();
}

So on disconnected:

    public override Task OnDisconnected()
    {
        UserHandler.ConnectedIds.Remove(this.Context.ConnectionId);
        if (UserHandler.ConnectedIds.Count == 0)
        {
               // STOP TASK -> SET CANCELLATION
        }
        return base.OnDisconnected();
    }

and on Connected:

    public override Task OnConnected()
    {
        Logger.Log.file.Info("[TaskActionStatus HUB => OnConnected] Start");

        UserHandler.ConnectedIds.Add(this.Context.ConnectionId);

        // start task only if at least one listener
        if (UserHandler.ConnectedIds.Count < 2)
        {
            // START A TASK -> (WHILE LOOP THAT GETS DATA FROM DB EVERY 2 SEC)
        }

        return base.OnConnected();
    }

Now, the problem arises when a users simply closes his/her browser window. There is no way for me to know if he/she disconnected.

So based on some question here, I would call each client and get a response. I'm not sure how to do it.

I guess I would have this:

public static void CheckConnectedUsers()
{
    var context = GlobalHost.ConnectionManager.GetHubContext<TaskActionStatus>();
    foreach (var connection in UserHandler.ConnectedIds)
    {
        context.Clients.Client(connection).verifyConnected("online?");
    }
}

BUT how do I get a response back form the client?

EDIT: steps that are executed:

I need the exact number of users connected because If there is at least one user connected I need to start a task. And I want to ensure that only 1 task is running for all connected users < 2 (start a task). suppose a situation like this: 2 users view a page that is using signalR. HashSet now contains 2 ids and a task is running. One closes his/her browser and after a few seconds and another refreshes his/hers. Now, the first one (the one that closed his/her browser did not execute OnDisconnected method so HashSet still has his/her ConnectionId, and the one that "refreshed" did execute OnDisonnected and then OnConnected which added his connectionId to HashSet. So instead of having only 1 ConnectionId in a HashSet and starting a task, HashSet contains 2 (old-not connected anymore and the one that just refreshed his/her browser), and the task never got started again.

thanks

回答1:

With SignalR 1.0, OnDisconnected should always fire, even when users close their window (the exception to this being if the server restarts).

OnDisconnected may not fire immediately, because if the client doesn't "abort" the connection it is considered "unclean" since there is a chance the client may try and reconnect (and if you reconnect you haven't disconnected according to SignalR's semantics).

By default, it should take about 30 seconds for the server to call OnDisconnected for an "unclean" disconnect. This can be reconfigured via GlobalHost.Configuration.DisconnectTimeout.



回答2:

I have just come across this same situation. The onDisconnect is not always fired. My solution was to poll the users occasionally to see if they are still connected.

Public Sub checkconnections()
    For Each s In users
        Clients.User(s).areYouThere()
    Next
    users = New List(Of String)
    System.Threading.Thread.Sleep(5000)
    checkconnections()
End Sub
Public Sub imHere()
    Dim id = GetClientId()
    If Not users.Contains(id) Then
        users.Add(id)
    End If
    Clients.All.sendCount(count)
End Sub

so every 5 seconds the hub sends to all clients in the users list then clears the list.

If the client receives the 'areYouThere' message it replies with 'imHere' which then gets added in to the list.

Hope this helps.