Как перебрать пользователей в ядре 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.");
}
}
}