Получите количество слушателей, клиентов, подключенных к концентратору SignalR

Есть ли способ узнать количество слушателей (клиентов, подключенных к хабу?)

Я пытаюсь запустить / запустить задачу, если подключен хотя бы один клиент, иначе не запускайте:

[HubName("taskActionStatus")]
public class TaskActionStatus : Hub, IDisconnect
{
    static CancellationTokenSource tokenSource;

    public void GetTasksStatus(int? siteId)
    {
        tokenSource = new CancellationTokenSource();
        CancellationToken ct = tokenSource.Token;

        ITaskRepository taskRepository = UnityContainerSetup.Container.Resolve<ITaskRepository>();

        // init task for checking task statuses
        var tasksItem = new DownloadTaskItem();
        taskRepository.GetTasksStatusAsync(siteId, tasksItem, ct);

        // subscribe to event [ listener ]
        tasksItem.Changed += new EventHandler<TaskEventArgs>(UpdateTasksStatus);
    }

    public void UpdateTasksStatus(object sender, TaskEventArgs e)
    {
        Clients.updateMessages(e.Tasks);
    }

    // when browsing away from page
    public Task Disconnect()
    {
        try
        {
            tokenSource.Cancel();
        }
        catch (Exception)
        {
            //
        }

        return null;
    }
}

Благодарность


person ShaneKm    schedule 22.11.2012    source источник
comment
Взгляните на заголовок stackoverflow.com/questions/21066657/   -  person KRoy    schedule 14.06.2018


Ответы (5)


Невозможно получить это количество от SignalR как такового. Вы должны использовать методы OnConnect() и OnDisconnect() на концентраторе, чтобы вести счет самостоятельно.

Простой пример со статическим классом для хранения счетчика:

public static class UserHandler
{
    public static HashSet<string> ConnectedIds = new HashSet<string>();
}

public class MyHub : Hub
{
    public override Task OnConnectedAsync()
    {
        UserHandler.ConnectedIds.Add(Context.ConnectionId);
        return base.OnConnectedAsync();
    }

    public override Task OnDisconnectedAsync(Exception exception)
    {
        UserHandler.ConnectedIds.Remove(Context.ConnectionId);
        return base.OnDisconnectedAsync(exception);
    }
}

Затем вы получаете счет от UserHandler.ConnectedIds.Count.

person Anders Arpi    schedule 22.11.2012
comment
у вас есть пример этого хоста? я бы сохранил этот список в сеансе? - person ShaneKm; 22.11.2012
comment
Обычно лучше вести счет на сервере в хранилище данных какого-либо типа (возможно, просто в статическом классе). Я могу наметить решение в своем ответе, дайте мне минутку ... - person Anders Arpi; 22.11.2012
comment
+1 просто помните, что при перезапуске домена приложения этот объект будет сброшен; вам следует подумать о том, чтобы сохранить этот объект в какой-то момент; Я обычно делаю это каждый раз, когда кого-то добавляют или удаляют. - person cillierscharl; 22.11.2012
comment
это странно, я получаю: signalR OnConnected () ': не найдено подходящего метода для переопределения. ?? - person ShaneKm; 23.11.2012
comment
Ах, тогда вы могли бы использовать старую версию SignalR (в настоящее время они претерпевают множество изменений для версии 1.0.0, которая на данный момент находится в альфа-версии). В этом случае реализуйте интерфейсы IConnect и IDisconnect и их соответствующие методы. - person Anders Arpi; 23.11.2012
comment
Использование статического класса, подобного этому, отлично работает, если вы когда-либо собираетесь запускать только один сервер, но если вы находитесь в облаке и используете балансировщик нагрузки между несколькими серверами, это решение разваливается. Однако вы можете использовать кеш-сервер для хранения подключенных пользователей. Мы используем Redis, размещенный в Azure. - person Anj; 21.11.2014
comment
@Anj Определенно, использование статического класса для хранения любых подобных данных (даже если это только кэшированные данные) обычно является плохой идеей из-за сценария, который вы упомянули. Для - person Anders Arpi; 07.01.2015
comment
@Anj Что произойдет, если сервер выйдет из строя? Будет ли корректироваться счетчик в базе? Хорошо, клиенты могут попытаться восстановить соединение, но если e. грамм. все серверы не работают, вы должны обнаружить это и сбросить счетчик на 0. Другая проблема возникает, если сервер выходит из строя и в то же время исчезает клиент. Остальные серверы обнаружат это? Есть идеи, как решить такие проблемы? - person Niklas Peter; 06.10.2015
comment
@NiklasPeter Какой сервер? Кеш-сервер или сервер приложений? Вы хотели бы иметь код запуска, чтобы гарантировать, что кеш инициализируется с соответствующим состоянием запуска. Не говоря уже о том, что если все ваши серверы выйдут из строя, количество подключенных клиентов signalR - далеко не самая большая проблема. - person Anj; 07.10.2015
comment
@Anj Сервер, на котором запущен сам SignalR, сервер приложений. Это не самая большая ваша проблема, но это беспокойство. Вы можете сохранить больше информации о слушателях, чем просто счетчик, и реализовать контрольный сигнал на уровне приложения для удаления потерянных клиентов. Однако на самом деле такая информация должна существовать внутри SignalR, но (как говорит MS) вы не можете запрашивать ее по дизайну. - person Niklas Peter; 07.10.2015
comment
Не забудьте переопределить OnReconnected в SignalR 2.2.1. Если клиент повторно подключается с тем же именем connection_id, OnConnect не вызывается. - person Yan Oreshchenkov; 20.03.2017
comment
В нем отсутствует параметр bool, чтобы переопределить метод OnDisconnected, я столкнулся с ошибкой компилятора: Не найдено подходящего метода для переопределения, его просто нужно изменить следующим образом: public override Task OnDisconnected(bool stopCalled) как кто-то еще упоминается в другом ответе справа ниже этого на. - person Muhammad Musavi; 17.01.2018
comment
static HashSet<string> ConnectedIds вообще не кажется потокобезопасным. - person Pang; 13.11.2020
comment
Да, следует использовать отслеживаемый HashSet с механизмом блокировки SemaphoreSlim. - person Vinigas; 19.01.2021

Для версии 2.1.1 ‹должно быть:

public static class UserHandler
{
    public static HashSet<string> ConnectedIds = new HashSet<string>();
}

public class MyHub : Hub
{
    public override Task OnConnected()
    {
        UserHandler.ConnectedIds.Add(Context.ConnectionId);
        return base.OnConnected();
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        UserHandler.ConnectedIds.Remove(Context.ConnectionId);
        return base.OnDisconnected(stopCalled);
    }
}
person Ogglas    schedule 25.09.2015
comment
Будьте осторожны с ним в случае шардинга сервера. Предпочитайте использовать Cache или Db для хранения ваших галопов. - person Nigrimmist; 14.10.2015
comment
Имейте в виду, что если ваше серверное приложение работает в Azure и масштабируется по вертикали, это не сработает. Вам нужен общий кеш, такой как Redis или база данных SQL / NoSQL (или любой другой общий ресурс), для отслеживания соединений. - person Andy; 28.04.2018
comment
теперь вам нужны OnConnectedAsync и OnDisconnectedAsync - person kofifus; 15.06.2018
comment
насколько мне известно, HasSet не является потокобезопасным, поэтому я думаю, что нам нужна некоторая синхронизация в этом подходе при доступе к ConnectedIds. - person teroplut; 29.03.2019

В SIgnalR (версия 2.4.1) довольно просто:

public int GetOnline()
{
   return GlobalHost.DependencyResolver.Resolve<ITransportHeartbeat>().GetConnections().Count;
}

Просто вызовите этот метод у клиента (:

person Лопатка Подзаборная    schedule 24.07.2019

Теперь вам нужно:

public override Task OnConnectedAsync()
{
    UserHandler.ConnectedIds.Add(Context.ConnectionId);

    return base.OnConnectedAsync();
}

public override Task OnDisconnectedAsync(Exception exception)
{
    UserHandler.ConnectedIds.Remove(Context.ConnectionId);
    return base.OnDisconnectedAsync(exception);
}
person ejdrian313    schedule 09.10.2018
comment
ИМХО, может, стоило отредактировать принятый ответ, а не добавлять новый? Помогает очистителю ниток получать меньше ответов. Кроме того, люди с большей вероятностью получат первый (и в данном случае принятый) ответ. - person LuvForAirplanes; 03.03.2020

Я хотел бы добавить, что если вы используете бессерверное решение с функциями Azure и службой Azure SignalR, существует следующая решенная проблема: https://github.com/Azure/azure-functions-signalrservice-extension/issues/54

Это относится к этому образцу, в котором вы можете использовать сетки событий для получения подсчета подключений в реальном времени, довольно мило. https://github.com/aspnet/AzureSignalR-samples/tree/master/samples/EventGridIntegration

person gerb0n    schedule 16.09.2020