Подтвердить что ты не робот

Как получить идентификатор соединения клиента signalR на стороне сервера?

Мне нужно получить идентификатор соединения клиента. Я знаю, что вы можете получить его со стороны клиента, используя $.connection.hub.id. Мне нужно войти в веб-службу, которая обновляет записи в базе данных, в свою очередь отображая обновление на веб-странице. Я новичок в 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. Функция show show в моем концентраторе такова:

//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 на мой веб-сервис?

Надеюсь, я не пытаюсь сделать что-то невозможное. Спасибо заранее.

4b9b3361

Ответ 1

Ответ тейлора работает, однако он не учитывает ситуацию, когда у пользователя открыты несколько вкладок веб-браузера, и поэтому у него несколько идентификаторов подключения.

Чтобы исправить это, я создал Concurrent Dictionary, где ключ словаря - это имя пользователя, а значение для каждого ключа - список текущих соединений для данного пользователя.

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

Ответ 2

Когда клиент вызывает функцию на стороне сервера, вы можете получить идентификатор своего подключения через Context.ConnectionId. Теперь, если вы хотите получить доступ к этому идентификатору соединения через механизм вне концентратора, вы можете:

  • Просто позвольте Hub вызывать ваш внешний метод, проходящий в идентификаторе соединения.
  • Управляйте списком подключенных клиентов, например, 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
    }
}

Пример 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

Надеюсь, это поможет!

Ответ 3

Я прошу разницы в повторном подключении. Клиент остается в списке, но подключится. Я делаю обновление статического списка для повторного подключения, чтобы решить эту проблему.