如何在服务器端获取signalR客户端的连接ID?

时间:2014-01-03 16:47:21

标签: c# asp.net-mvc signalr

我需要获取客户端的连接ID。我知道你可以使用$.connection.hub.id从客户端获取它。我需要的是在我拥有的Web服务中进入更新数据库中的记录,然后在网页上显示更新。我是signalR和stackoverflow的新手,所以任何建议都会受到赞赏。在我的客户端网页上,我有这个:

<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>

一切正常,直到我想使用signalR更新页面。我的中心的节目通知功能是:

//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

如何将connectionid发送到我的网络服务?

希望我不是想做一些不可能的事情。提前谢谢。

3 个答案:

答案 0 :(得分:69)

当客户端在服务器端调用函数时,您可以通过Context.ConnectionId检索其连接ID。现在,如果您想通过集线器外部的机制访问该连接ID,您可以:

  1. 让Hub调用传递连接ID的外部方法。
  2. 通过添加public static ConcurrentDictionary<string, MyUserType>...中的字典并在OnConnected中删除字典来管理已知连接的客户列表,例如OnDisconnected。获得用户列表后,您可以通过外部机制查询它。
  3. 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
        }
    }
    

    前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
    

    希望这有帮助!

答案 1 :(得分:5)

我不同意重新连接。客户端仍在列表中,但是connectid将会更改。我在重新连接时对静态列表进行了更新以解决此问题。

答案 2 :(得分:5)

Taylor的答案有效,但是,它没有考虑到用户打开了多个Web浏览器选项卡并因此具有多个不同的连接ID的情况。

要解决此问题,我创建了一个并发字典,其中字典键是用户名,每个键的值是该给定用户的当前连接列表。

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

连接时-将连接添加到全局缓存字典:

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

在断开连接(关闭选项卡)时-从全局缓存字典中删除连接:

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