Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
Группы в SignalR представляют коллекцию подключений, которые ассоциированы с именем группы. SignalR позволяет добавлять и удалять клиентов из группы. Один клиент может входить сразу в несколько групп.
Для работы с группами в классе Hub определено свойство Groups, которое представляет объект IGroupManager. Он имеет два метода:
AddToGroupAsync(connectionId, groupName): добавляет клиента с идентификатором connectionId в группу с именем groupName
RemoveFromGroupAsync(connectionId, groupName): удаляет клиента с идентификатором connectionId из группы
Также у объекта IHubCallerClients определено ряд методов, которые позволяют выбрать определенные группы для отправки им сообщения.
Например, определим следующий хаб:
using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; using System; namespace SignalRApp { public class ChatHub : Hub { string groupname = "cats"; public async Task Enter(string username) { if (String.IsNullOrEmpty(username)) { await Clients.Caller.SendAsync("Notify", "Для входа в чат введите логин"); } else { await Groups.AddToGroupAsync(Context.ConnectionId, groupname); await Clients.Group(groupname).SendAsync("Notify", $"{username} вошел в чат"); } } public async Task Send(string message, string username) { await Clients.Group(groupname).SendAsync("Receive", message, username); } } }
В хабе определено два метода. В методе Enter обратившегося клиента добавляют в группу "cats". Имя групп может быть любым, важно только учитывать, что оно регистрозависимое. В методе Send ретранслируют сообщение клиента всем участникам группы cats.
Для вызова метода у клиентов в группах можно использовать ряд методов:
Group(string groupName): вызывает метод у клиентов определенной группы
GroupExcept(string groupName, IReadOnlyList<string> connectionIds): вызывает метод у клиентов группы по имени groupName за исключением тех клиентов, id которых передаются в качестве второго параметра
Groups(IReadOnlyList<string> groupNames): вызывает метод у клиентов групп, названия которых передаются в метод
OthersInGroup(string OthersInGroup): вызывает метод у клиентов определенной группы за исключением текущего клиента
Для тестирования можно определить следующую веб-страницу:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>SignalR Chat</title> </head> <body> <div id="loginBlock"> Ввойти в чат:<br /> <input id="userName" type="text" /> <input id="loginBtn" type="button" value="Войти" /> </div><br /> <div id="header"></div><br /> <div id="inputForm"> <input type="text" id="message" /> <input type="button" id="sendBtn" value="Отправить" /> </div> <div id="chatroom"></div> <script src="js/signalr/dist/browser/signalr.min.js"></script> <script> const hubConnection = new signalR.HubConnectionBuilder() .withUrl("/chat") .build(); let userName = ""; // получение сообщения от сервера hubConnection.on("Receive", function (message, userName) { // создаем элемент <b> для имени пользователя let userNameElem = document.createElement("b"); userNameElem.appendChild(document.createTextNode(userName + ": ")); // создает элемент <p> для сообщения пользователя let elem = document.createElement("p"); elem.appendChild(userNameElem); elem.appendChild(document.createTextNode(message)); var firstElem = document.getElementById("chatroom").firstChild; document.getElementById("chatroom").insertBefore(elem, firstElem); }); // диагностическое сообщение hubConnection.on("Notify", function (message) { let elem = document.createElement("p"); elem.appendChild(document.createTextNode(message)); var firstElem = document.getElementById("chatroom").firstChild; document.getElementById("chatroom").insertBefore(elem, firstElem); }); // установка имени пользователя document.getElementById("loginBtn").addEventListener("click", function (e) { userName = document.getElementById("userName").value; hubConnection.invoke("Enter", userName); }); // отправка сообщения на сервер document.getElementById("sendBtn").addEventListener("click", function (e) { let message = document.getElementById("message").value; hubConnection.invoke("Send", message, userName); }); hubConnection.start(); </script> </body> </html>
При работе с группами стоит учитывать, группа никак не связана с аутентификацией и авторизацией. Например, в примере хаба выше любой подключившийся к хабу и не состояющий в группе "cats", может обратиться к методу Send и отправить сообщение в эту группу, только это сообщение будет видно только членам этой группы. Группа в SignalR - это не более чем условное объединение клиентов, подключенных к хабу. И мы не можем узнать, какие пользователи состоят в той или иной группе, получить всех пользователей определенной группы.
И если, к примеру, необходимо, создавать какие-нибудь групповые чаты, где могут послать сообщения и соответственно видеть эти сообщения только участники данного чата, необходимо использовать стандартные механизмы авторизации и аутентификации. Например:
[Authorize(Roles="admin")] public async Task Send(string message, string username) { await Clients.Group("admins").SendAsync("Send", message, username); }
В данном случае в группу "admins" могут посылать сообщения только авторизованные пользователи, у которых роль - "admin".