Как перебрать пользователей в ядре asp.net SignalR?

В приложении SignalR на ядре.net у меня есть рабочий фрагмент кода, подобный следующему:

public Task SendPrivateMessage(string user, string message)
{
    var sender = Context.User.Claims.FirstOrDefault(cl => cl.Type == "username")?.Value;
    return Clients.User(user)
                  .SendAsync("ReceiveMessage", $"Message from {sender}: {message}");
}

Это отправляет сообщение от текущего подключенного пользователя указанному пользователю.

Теперь я хотел бы отправить индивидуальное сообщение каждому подключенному пользователю; что-то вроде следующего понятия:

public Task UpdateMessageStatus()
{
    foreach(client in Clients.Users)
    {
         var nrOfMessages = GetMessageCount();
         client.SendAsync($"You have {nrOfMessages} messages.");
    }
}

Как я могу достичь этого; т.е. как я могу перебирать подключенных пользователей и отправлять отдельные сообщения каждому из них?

Редактировать / уточнение

Как уже упоминалось, мне нужно было отправлять отдельные (то есть специализированные) сообщения каждому подключенному пользователю, поэтому с помощью Clients.All не был выбран, так как это можно использовать только для отправки одного и того же сообщения всем подключенным пользователям.

Я закончил тем, что делал что-то похожее на то, что Марк С. опубликовал в принятом ответе.

3 ответа

Решение

Если вы застряли на неиспользовании Clients.All API, который предоставляется вам, вы можете хранить локальный кеш подключенных пользователей и использовать его в качестве списка подключенных пользователей.

Что-то вроде этого:

static HashSet<string> CurrentConnections = new HashSet<string>();

    public override Task OnConnected()
    {
        var id = Context.ConnectionId;
        CurrentConnections.Add(id);

        return base.OnConnected();
    }

    public Task SendAllClientsMessage()
    {
        foreach (var activeConnection in GetAllActiveConnections())
        {
            Clients.Client(activeConnection).SendMessageAsync("Hi");
        }
    }

    public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
    {
        var connection = CurrentConnections.FirstOrDefault(x => x == Context.ConnectionId);

        if (connection != null)
        {
            CurrentConnections.Remove(connection);
        }

        return base.OnDisconnected(stopCalled);
    }


    //return list of all active connections
    public List<string> GetAllActiveConnections()
    {
        return CurrentConnections.ToList();
    }

Вы можете использовать Clients.All, чтобы отправить сообщение всем вашим клиентам.

return Clients.All.SendAsync ("ReceiveMessage", $ "Сообщение от {sender}: {message}");

Я закончил тем, что создал свой собственный список подключенных пользователей, аналогичный ответу, предоставленному Марком С.

Если немного расширить его, это позволит мне сделать что-то вроде следующей концепции:

public async Task CheckAllMessages()
{
    foreach (var user in ConnectedUsers)
    {
       var nr = GetNrOfMessagesForUser(user);
       if(nr > 0)
       {
           await Clients.User(user)
                        .SendAsync("ReceiveMessage", 
                                   $"User ({user}) has {nr} new messages waiting.");
       }
    }
}
Другие вопросы по тегам