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

Cli*_*t L 44 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>
Run Code Online (Sandbox Code Playgroud)

一切正常,直到我想使用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
Run Code Online (Sandbox Code Playgroud)

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

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

N. *_*len 71

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

  1. 让Hub调用传递连接ID的外部方法.
  2. 管理已连接客户端的列表,例如public static ConcurrentDictionary<string, MyUserType>...通过添加到字典中OnConnected并从中删除OnDisconnected.获得用户列表后,您可以通过外部机制查询.

例1:

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

例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
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!

  • 无需在重新连接时添加或删除客户端. (3认同)

Mat*_*w C 12

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

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

public static ConcurrentDictionary<string, List<string>> ConnectedUsers = new ConcurrentDictionary<string, List<string>>();
Run Code Online (Sandbox Code Playgroud)

On Connected - 添加到全局缓存字典的连接:

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();
}
Run Code Online (Sandbox Code Playgroud)

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

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此解决方案不是完全线程安全的,它仅在不同用户连接或断开连接时才是线程安全的,但如果一个用户同时在不同选项卡中连接,现有的UserConnectionIds添加/删除将处于竞争状态。为了获得完整的解决方案,您还应该锁定现有的UserConnectionIds 列表。 (3认同)

Jef*_*eff 5

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

  • 你是怎样做的? (4认同)