Search code examples
c#asp.net-mvcsignalr

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


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 service I have which updates records in a database, in turn displaying the update on a web page. I am new to signalR and stackoverflow, so any advice would be appreciated. On my client web page I have this:

<script type="text/javascript">
    $(function () {
        // Declare a proxy to reference the hub. 
        var notify = $.connection.notificationHub;
        
        // Create a function that the hub can call to broadcast messages.
        notify.client.broadcastMessage = function (message) {
            var encodedMsg = $('<div />').text(message).html();// Html encode display message.
            $('#notificationMessageDisplay').append(encodedMsg);// Add the message to the page.
        };//end broadcastMessage
                 
        // Start the connection.
        $.connection.hub.start().done(function () {
            $('#btnUpdate').click(function () {
                //call showNotification method on hub
                notify.server.showNotification($.connection.hub.id, "TEST status");
            });
        });

        
    });//End Main function

    
</script>

everything works up until I want to update the page using signalR. The show notification function in my hub is this:

//hub function
public void showNotification(string connectionId, string newStatus){               
    IHubContext context = GlobalHost.ConnectionManager.GetHubContext<notificationHub>();
    string connection = "Your connection ID is : " + connectionId;//display for testing
    string statusUpdate = "The current status of your request is: " + newStatus;//to be displayed
    //for testing, you can display the connectionId in the broadcast message
    context.Clients.Client(connectionId).broadcastMessage(connection + " " + statusUpdate);
}//end show notification

how can I send the connectionid to my web service?

Hopefully I'm not trying to do something impossible.


Solution

  • 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);
    }