How to obtain connection ID of signalR client on the server side?

前端 未结 3 1261

I need to get the connection ID of a client. I know you can get it from the client side using $.connection.hub.id. What I need is to get in while in a web servi

相关标签:
3条回答
  • 2020-12-12 16:49

    I beg to differ on the reconnect. The client remains in the list but the connectid will change. I do an update to the static list on reconnects to resolve this.

    0 讨论(0)
  • 2020-12-12 17:07

    Taylor's answer works, however, it doesn't take into consideration a situation where a user has multiple web browser tabs opened and therefore has multiple different connection IDs.

    To fix that, I created a Concurrent Dictionary where the dictionary key is a user name and the value for each key is a List of current connections for that given user.

    public static ConcurrentDictionary<string, List<string>> ConnectedUsers = new ConcurrentDictionary<string, List<string>>();
    

    On Connected - Adding a connection to the global cache dictionary:

    public override Task OnConnected()
    {
        Trace.TraceInformation("MapHub started. ID: {0}", Context.ConnectionId);
        
        var userName = "testUserName1"; // or get it from Context.User.Identity.Name;
    
        // Try to get a List of existing user connections from the cache
        List<string> existingUserConnectionIds;
        ConnectedUsers.TryGetValue(userName, out existingUserConnectionIds);
    
        // happens on the very first connection from the user
        if(existingUserConnectionIds == null)
        {
            existingUserConnectionIds = new List<string>();
        }
    
        // First add to a List of existing user connections (i.e. multiple web browser tabs)
        existingUserConnectionIds.Add(Context.ConnectionId);
    
        
        // Add to the global dictionary of connected users
        ConnectedUsers.TryAdd(userName, existingUserConnectionIds);
    
        return base.OnConnected();
    }
    

    On disconnecting (closing the tab) - Removing a connection from the global cache dictionary:

    public override Task OnDisconnected(bool stopCalled)
    {
        var userName = Context.User.Identity.Name;
    
        List<string> existingUserConnectionIds;
        ConnectedUsers.TryGetValue(userName, out existingUserConnectionIds);
    
        // remove the connection id from the List 
        existingUserConnectionIds.Remove(Context.ConnectionId);
    
        // If there are no connection ids in the List, delete the user from the global cache (ConnectedUsers).
        if(existingUserConnectionIds.Count == 0)
        {
            // if there are no connections for the user,
            // just delete the userName key from the ConnectedUsers concurent dictionary
            List<string> garbage; // to be collected by the Garbage Collector
            ConnectedUsers.TryRemove(userName, out garbage);
        }
    
        return base.OnDisconnected(stopCalled);
    }
    
    0 讨论(0)
  • 2020-12-12 17:10

    When a client invokes a function on the server side you can retrieve their connection ID via Context.ConnectionId. Now, if you'd like to access that connection Id via a mechanism outside of a hub, you could:

    1. Just have the Hub invoke your external method passing in the connection id.
    2. Manage a list of connected clients aka like public static ConcurrentDictionary<string, MyUserType>... by adding to the dictionary in OnConnected and removing from it in OnDisconnected. Once you have your list of users you can then query it via your external mechanism.

    Ex 1:

    public class MyHub : Hub
    {
        public void AHubMethod(string message)
        {
            MyExternalSingleton.InvokeAMethod(Context.ConnectionId); // Send the current clients connection id to your external service
        }
    }
    

    Ex 2:

    public class MyHub : Hub
    {
        public static ConcurrentDictionary<string, MyUserType> MyUsers = new ConcurrentDictionary<string, MyUserType>();
    
        public override Task OnConnected()
        {
            MyUsers.TryAdd(Context.ConnectionId, new MyUserType() { ConnectionId = Context.ConnectionId });
            return base.OnConnected();
        }
    
        public override Task OnDisconnected(bool stopCalled)
        {
            MyUserType garbage;
    
            MyUsers.TryRemove(Context.ConnectionId, out garbage);
    
            return base.OnDisconnected(stopCalled);
        }
    
        public void PushData(){
            //Values is copy-on-read but Clients.Clients expects IList, hence ToList()
            Clients.Clients(MyUsers.Keys.ToList()).ClientBoundEvent(data);
        }
    }
    
    public class MyUserType
    {
        public string ConnectionId { get; set; }
        // Can have whatever you want here
    }
    
    // Your external procedure then has access to all users via MyHub.MyUsers
    

    Hope this helps!

    0 讨论(0)
提交回复
热议问题