Группы

Последнее обновление: 07.08.2022

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

Для работы с группами в классе Hub определено свойство Groups, которое представляет объект IGroupManager. Он имеет два метода:

  • AddToGroupAsync(connectionId, groupName): добавляет клиента с идентификатором connectionId в группу с именем groupName

  • RemoveFromGroupAsync(connectionId, groupName): удаляет клиента с идентификатором connectionId из группы

Также у объекта IHubCallerClients определено ряд методов, которые позволяют выбрать определенные группы для отправки им сообщения. Для вызова метода у клиентов в группах можно использовать ряд методов:

  • Group(string groupName): вызывает метод у клиентов определенной группы

  • GroupExcept(string groupName, IReadOnlyList<string> connectionIds): вызывает метод у клиентов группы по имени groupName за исключением тех клиентов, id которых передаются в качестве второго параметра

  • Groups(IReadOnlyList<string> groupNames): вызывает метод у клиентов групп, названия которых передаются в метод

  • OthersInGroup(string OthersInGroup): вызывает метод у клиентов определенной группы за исключением текущего клиента

Например, определим следующий хаб:

using Microsoft.AspNetCore.SignalR;

namespace SignalRApp
{
    public class ChatHub : Hub
    {
        public async Task Enter(string username, string groupName)
        {
            await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
            await Clients.All.SendAsync("Notify", $"{username} вошел в чат в группу {groupName}");
        }
        public async Task Send(string message, string userName, string groupName)
        {
            await Clients.Group(groupName).SendAsync("Receive", message, userName);
        }
    }
}

В хабе определено два метода. В методе Enter хаб получает имя пользователя и группы, в которую он вошел. Имя групп может быть любым, важно только учитывать, что оно регистрозависимое. Пользователь добавляется в эту группу, а всем клиентам отправляется соответствующее сообщение.

В методе Send ретранслируют сообщение клиента всем участникам определенной группы.

Для тестирования можно определить следующую веб-страницу index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>METANIT.COM</title>
</head>
<body>
    <div id="loginBlock">
        Введите логин и группу:<br />
        <input id="userName" type="text" placeholder="Введите логин" /> 
        <input id="userGroup" type="text" placeholder="Введите группу" />
        <input id="loginBtn" type="button" value="Войти" />
    </div><br />


    <div id="inputForm">
        Сообщение:<br />
        <input type="text" id="message" />
        <input type="button" id="sendBtn" value="Отправить" />
    </div>
    <div id="chatroom"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>
    <script>
        let userName = "";
        let userGroup = "";
        const hubConnection = new signalR.HubConnectionBuilder()
            .withUrl("/chat")
            .build();

        // установка имени пользователя и вход в группу
        document.getElementById("loginBtn").addEventListener("click", function (e) {
            userName = document.getElementById("userName").value;
            userGroup = document.getElementById("userGroup").value;
            hubConnection.invoke("Enter", userName, userGroup);
        });

        // отправка сообщения в группу
        document.getElementById("sendBtn").addEventListener("click", () => {

            const message = document.getElementById("message").value;
            hubConnection.invoke("Send", message, userName, userGroup)
                .catch(error => console.error(error));
        });

        // получение сообщения для определенной группы
        hubConnection.on("Receive", (message, user) => {

            // создаем элемент <b> для имени пользователя
            const userNameElem = document.createElement("b");
            userNameElem.textContent = `${user}: `;

            // создает элемент <p> для сообщения пользователя
            const elem = document.createElement("p");
            elem.appendChild(userNameElem);
            elem.appendChild(document.createTextNode(message));

            const firstElem = document.getElementById("chatroom").firstChild;
            document.getElementById("chatroom").insertBefore(elem, firstElem);
        });

        // получение общего уведомления
        hubConnection.on("Notify", message => {

            const elem = document.createElement("p");
            elem.textContent = message;

            const firstElem = document.getElementById("chatroom").firstChild;
            document.getElementById("chatroom").insertBefore(elem, firstElem);
        });

        hubConnection.start()
            .then(() => {
                document.getElementById("sendBtn").disabled = false;
                document.getElementById("loginBtn").disabled = false
            })
            .catch ((err) => console.error(err));
    </script>
</body>
</html>

Здесь по нажатию на кнопку loginBtn хабу отправляется имя пользователя и его группы. А по нажатию на кнопку sendBtn отправляется сообщение с указанием имени пользователя и его группы.

Для тестирования определим в файле Program.cs следующий код:

using SignalRApp;   // пространство имен класса ChatHub

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSignalR();
var app = builder.Build();

app.UseDefaultFiles();
app.UseStaticFiles();

app.MapHub<ChatHub>("/chat");
app.Run();

Пример работы:

Группы в SignalR в приложении на ASP.NET Core и C#

Так, в примере выше пользователи Tom и Sam принадлежат группе .net developers, поэтому только они видят сообщения, предназначенные для этой группы. А пользователь Bob, который принадлежит группе "java developers", не видит эти сообщения. Ему доступны только общие сообщения.

При работе с группами стоит учитывать, группа никак не связана с аутентификацией и авторизацией. Например, в примере хаба выше любой подключившийся к хабу и не состояющий в определенной группе, может обратиться к методу Send и отправить сообщение в эту группу, только это сообщение будет видно только членам этой группы. Группа в SignalR - это не более чем условное объединение клиентов, подключенных к хабу. И мы не можем узнать, какие пользователи состоят в той или иной группе, получить всех пользователей определенной группы.

И если, к примеру, необходимо, создавать какие-нибудь групповые чаты, где могут послать сообщения и соответственно видеть эти сообщения только участники данного чата, необходимо использовать стандартные механизмы авторизации и аутентификации. Например:

[Authorize(Roles="admin")]
public async Task Send(string message, string username)
{
	await Clients.Group("admins").SendAsync("Send", message, username);
}

В данном случае в группу "admins" могут посылать сообщения только авторизованные пользователи, у которых роль - "admin".

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850