Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
SignalR API Hubs позволяет подключенным клиентам вызывать методы на сервере, обеспечивая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. SignalR кроме того, обеспечивает непрямую связь между клиентами и клиентами, всегда опосредованную SignalR центром, позволяя отправлять сообщения между отдельными клиентами, группами или всеми подключенными клиентами. SignalR позаботится обо всем необходимом, чтобы обеспечить возможность обмена данными между клиентами и серверами в режиме реального времени.
Настройка SignalR центров
Чтобы зарегистрировать службы, необходимые для центров SignalR, вызовите AddSignalR в Program.cs.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Чтобы настроить SignalR конечные точки, вызовите MapHubтакже в Program.cs:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Note
Серверные сборки ASP.NET Core теперь устанавливаются с пакетом SDK для .NET Core. См. SignalR сборки в общем фреймворке для получения дополнительной информации.
Создание и использование центров
Создайте концентратор, объявив класс, наследуемый от Hub. Добавьте public методы в класс, чтобы сделать их вызываемыми из клиентов:
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
- Не сохраняйте состояние в свойстве класса концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр хаба непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext. - Используйте
awaitпри вызове асинхронных методов, которые зависят от поддержания работоспособности хаба. Например, методClients.All.SendAsync(...)может завершиться ошибкой, если его вызывают безawait, и метод концентратора завершается до завершенияSendAsync.
Объект Context
Класс Hub содержит Context свойство, содержащее следующие свойства со сведениями о подключении:
| Property | Description |
|---|---|
| ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
| UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR использует ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением в качестве идентификатора пользователя. |
| User | Возвращает ClaimsPrincipal, связанный с текущим пользователем. |
| Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
| Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
| ConnectionAborted | Получает объект CancellationToken, который уведомляет о прерывании подключения. |
Hub.Context также содержит следующие методы:
| Method | Description |
|---|---|
| GetHttpContext | Возвращает HttpContext для подключения или null, если подключение не связано с HTTP-запросом. Для HTTP-подключений используйте этот метод для получения таких сведений, как заголовки HTTP и строки запроса. |
| Abort | Прерывает подключение. |
Объект Клиенты
Класс Hub содержит свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
| Property | Description |
|---|---|
| All | Вызывает метод для всех подключенных клиентов |
| Caller | Вызывает метод у клиента, который инициировал вызов метода концентратора. |
| Others | Вызывает метод для всех подключенных клиентов, кроме клиента, вызвавшего этот метод |
Hub.Clients также содержит следующие методы:
| Method | Description |
|---|---|
| AllExcept | Вызывает метод для всех подключенных клиентов, за исключением указанных подключений. |
| Client | Вызывает метод для определенного подключенного клиента. |
| Clients | Вызывает метод для определенных подключенных клиентов |
| Group | Вызывает метод для всех подключений в указанной группе |
| GroupExcept | Вызывает метод для всех подключений в указанной группе, за исключением указанных подключений. |
| Groups | Вызывает метод для нескольких групп подключений |
| OthersInGroup | Вызывает метод в группе подключений, исключая клиента, который инициировал вызов метода узла. |
| User | Вызывает метод для всех подключений, связанных с конкретным пользователем |
| Users | Вызывает метод для всех подключений, связанных с указанными пользователями |
Каждое свойство или метод в предыдущих таблицах возвращает объект с методом SendAsync . Метод SendAsync получает имя метода клиента для вызова и любых параметров.
Объект, возвращаемый методами Client и Caller, также содержит метод InvokeAsync, который можно использовать, чтобы дождаться результата от клиента.
Отправка сообщений клиентам
Чтобы выполнить вызовы к определенным клиентам, используйте свойства Clients объекта. В следующем примере существуют три узловых метода:
-
SendMessageотправляет сообщение всем подключенным клиентам с помощьюClients.All. -
SendMessageToCallerотправляет сообщение обратно вызывающей стороне с помощьюClients.Caller. -
SendMessageToGroupотправляет сообщение всем клиентам вSignalR Usersгруппе.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Строго типизированные центры
Недостаток использования SendAsync заключается в том, что он использует строку для указания вызываемого метода клиента. При этом код остается открытым для ошибок среды выполнения, если имя метода пропущено или отсутствует в клиенте.
Альтернативой использованию SendAsync является строго типизированный класс Hub с Hub<T>. В следующем примере метод ChatHub клиента был выделен в интерфейс под названием IChatClient.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Этот интерфейс можно использовать для рефакторинга предыдущего примера ChatHub, чтобы он стал строго типизированным.
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
Использование Hub<IChatClient> включает проверку времени компиляции клиентских методов. Это предотвращает проблемы, вызванные использованием строк, так как Hub<T> может предоставлять доступ только к методам, определенным в интерфейсе. Использование строго типизированного Hub<T> отключает возможность использования SendAsync.
Note
Суффикс Async не удаляется из имен методов. Если метод клиента не определен с помощью .on('MyMethodAsync'), не используйте MyMethodAsync в качестве имени.
Результаты клиента
Помимо вызова клиентов, сервер может запросить результат от клиента. Для этого требуется, чтобы сервер использовал ISingleClientProxy.InvokeAsync, а клиент возвращал результат от своего обработчика .On.
Существует два способа использования API на сервере, во-первых — вызов Client(...) или Caller на свойстве Clients в методе Hub.
public class ChatHub : Hub
{
public async Task<string> WaitForMessage(string connectionId)
{
var message = await Clients.Client(connectionId).InvokeAsync<string>(
"GetMessage");
return message;
}
}
Второй способ — вызвать Client(...) на экземпляре IHubContext<T>:
async Task SomeMethod(IHubContext<MyHub> context)
{
string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
"GetMessage");
}
Строго типизированные концентраторы также могут возвращать значения из методов интерфейса:
public interface IClient
{
Task<string> GetMessage();
}
public class ChatHub : Hub<IClient>
{
public async Task<string> WaitForMessage(string connectionId)
{
string message = await Clients.Client(connectionId).GetMessage();
return message;
}
}
Клиенты возвращают результаты в обработчиках .On(...), как показано ниже:
Клиент .NET
hubConnection.On("GetMessage", async () =>
{
Console.WriteLine("Enter message:");
var message = await Console.In.ReadLineAsync();
return message;
});
Клиент Typescript
hubConnection.on("GetMessage", async () => {
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("message");
}, 100);
});
return promise;
});
Клиент на Java
hubConnection.onWithResult("GetMessage", () -> {
return Single.just("message");
});
Изменение имени метода хаба
По умолчанию имя метода концентратора сервера — это имя метода .NET. Чтобы изменить это поведение по умолчанию для определенного метода, используйте атрибут HubMethodName . Клиент должен использовать это имя вместо имени метода .NET при вызове метода:
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Внедрение служб в концентратор
Конструкторы хабов могут принимать службы из системы внедрения зависимостей в виде параметров, которые можно хранить в свойства класса для использования в методах хаба.
При внедрении нескольких служб для различных методов хаба или как альтернативный способ написания кода, методы хаба также могут принимать службы из DI. По умолчанию параметры метода узла, если это возможно, проверяются и устраняются из DI.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message, IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Если не требуется неявное разрешение параметров из служб, отключите его с DisableImplicitFromServicesParameters.
Чтобы явно указать, какие параметры разрешаются из DI в методах концентратора, используйте опцию DisableImplicitFromServicesParameters и атрибут [FromServices] или настраиваемый атрибут, реализующий IFromServiceMetadata, на параметрах метода концентратора, которые должны разрешаться из DI.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message,
[FromServices] IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Note
Эта функция использует IServiceProviderIsService, который может быть реализован при необходимости реализациями DI. Если контейнер DI приложения не поддерживает эту функцию, внедрение служб в методы концентратора не поддерживается.
Поддержка ключевых служб в инъекции зависимостей
Ключевые службы — это механизм регистрации и получения служб внедрения зависимостей (DI) посредством использования ключей. Служба связана с ключом путем вызова AddKeyedSingleton (или AddKeyedScopedAddKeyedTransient) для регистрации. Доступ к зарегистрированной службе путем указания ключа с атрибутом [FromKeyedServices] . В следующем коде показано, как использовать ключи служб:
using Microsoft.AspNetCore.SignalR;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
var app = builder.Build();
app.MapRazorPages();
app.MapHub<MyHub>("/myHub");
app.Run();
public interface ICache
{
object Get(string key);
}
public class BigCache : ICache
{
public object Get(string key) => $"Resolving {key} from big cache.";
}
public class SmallCache : ICache
{
public object Get(string key) => $"Resolving {key} from small cache.";
}
public class MyHub : Hub
{
public void SmallCacheMethod([FromKeyedServices("small")] ICache cache)
{
Console.WriteLine(cache.Get("signalr"));
}
public void BigCacheMethod([FromKeyedServices("big")] ICache cache)
{
Console.WriteLine(cache.Get("signalr"));
}
}
Обработка событий для подключения
SignalR API системы Центров предоставляет OnConnectedAsync и OnDisconnectedAsync виртуальные методы для управления и отслеживания соединений. Переопределите виртуальный OnConnectedAsync метод для выполнения действий, когда клиент подключается к центру, например добавление его в группу:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Переопределите виртуальный OnDisconnectedAsync метод для выполнения действий при отключении клиента. Если клиент намеренно отключается, например путем вызова connection.stop(), exception параметр имеет значение null. Однако если клиент отключается из-за ошибки, например сбоя сети, exception параметр содержит исключение, описывающее сбой:
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync не нужно вызывать в OnDisconnectedAsync, это обрабатывается автоматически.
Управление ошибками
Исключения, возникающие в методах хабов, отправляются клиенту, который вызвал метод. В клиенте JavaScript метод invoke возвращает JavaScript Promise. Клиенты могут присоединить catch обработчик к возвращаемому обещанию или использовать try/catch для async/await обработки исключений.
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Подключения не закрываются, когда концентратор создает исключение. По умолчанию SignalR возвращается универсальное сообщение об ошибке клиенту, как показано в следующем примере:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.
Непредвиденные исключения часто содержат конфиденциальную информацию, например, имя сервера базы данных в случае, если соединение с базой данных прерывается. SignalR не предоставляет эти подробные сообщения об ошибках по умолчанию в качестве меры безопасности. Дополнительные сведения о том, почему сведения об исключении подавляются, см.: в разделе "Вопросы безопасности" в ASP.NET Core SignalR.
Если исключительное условие должно распространяться на клиент, используйте HubException класс.
HubException Если в методе концентратора создается исключение, SignalRотправляется клиенту все сообщение об исключении, не измененное:
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Note
SignalR отправляет клиенту только свойство Message исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
SignalR API Hubs позволяет подключенным клиентам вызывать методы на сервере, обеспечивая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. SignalR кроме того, обеспечивает непрямую связь между клиентами и клиентами, всегда опосредованную SignalR центром, позволяя отправлять сообщения между отдельными клиентами, группами или всеми подключенными клиентами. SignalR позаботится обо всем необходимом, чтобы обеспечить возможность обмена данными между клиентами и серверами в режиме реального времени.
Настройка SignalR центров
Чтобы зарегистрировать службы, необходимые для центров SignalR, вызовите AddSignalR в Program.cs.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Чтобы настроить SignalR конечные точки, вызовите MapHubтакже в Program.cs:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Note
Серверные сборки ASP.NET Core теперь устанавливаются с пакетом SDK для .NET Core. См. SignalR сборки в общем фреймворке для получения дополнительной информации.
Создание и использование центров
Создайте концентратор, объявив класс, наследуемый от Hub. Добавьте public методы в класс, чтобы сделать их вызываемыми из клиентов:
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
- Не сохраняйте состояние в свойстве класса концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр хаба непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext. - Используйте
awaitпри вызове асинхронных методов, которые зависят от поддержания работоспособности хаба. Например, методClients.All.SendAsync(...)может завершиться ошибкой, если его вызывают безawait, и метод концентратора завершается до завершенияSendAsync.
Объект Context
Класс Hub содержит Context свойство, содержащее следующие свойства со сведениями о подключении:
| Property | Description |
|---|---|
| ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
| UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR использует ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением в качестве идентификатора пользователя. |
| User | Возвращает ClaimsPrincipal, связанный с текущим пользователем. |
| Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
| Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
| ConnectionAborted | Получает CancellationToken, который уведомляет о прерывании подключения. |
Hub.Context также содержит следующие методы:
| Method | Description |
|---|---|
| GetHttpContext | Возвращает HttpContext для подключения или null, если подключение не связано с HTTP-запросом. Для HTTP-подключений используйте этот метод для получения таких сведений, как заголовки HTTP и строки запроса. |
| Abort | Прерывает подключение. |
Объект Client
Класс Hub содержит свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
| Property | Description |
|---|---|
| All | Вызывает метод для всех подключенных клиентов |
| Caller | Вызывает метод на клиенте, который вызвал метод хаба. |
| Others | Вызывает метод для всех подключенных клиентов, исключая клиента, который вызвал метод |
Hub.Clients также содержит следующие методы:
| Method | Description |
|---|---|
| AllExcept | Вызывает метод для всех подключенных клиентов, кроме указанных подключений. |
| Client | Вызывает метод для определенного подключенного клиента. |
| Clients | Вызывает метод для определенных подключенных клиентов |
| Group | Вызывает метод для всех подключений в указанной группе |
| GroupExcept | Вызывает метод для всех подключений в указанной группе, за исключением указанных подключений. |
| Groups | Вызывает метод для нескольких групп подключений |
| OthersInGroup | Вызывает метод в группе подключений, исключая клиента, который инициировал вызов метода узла. |
| User | Вызывает метод для всех подключений, связанных с конкретным пользователем |
| Users | Вызывает метод для всех подключений, связанных с указанными пользователями |
Каждое свойство или метод в предыдущих таблицах возвращает объект с методом SendAsync . Метод SendAsync получает имя метода клиента для вызова и любых параметров.
Объект, возвращаемый методами Client и Caller, также содержит метод InvokeAsync, который можно использовать, чтобы дождаться результата от клиента.
Отправка сообщений клиентам
Чтобы выполнить вызовы к определенным клиентам, используйте свойства Clients объекта. В следующем примере существуют три узловых метода:
-
SendMessageотправляет сообщение всем подключенным клиентам с помощьюClients.All. -
SendMessageToCallerотправляет сообщение обратно вызывающей стороне с помощьюClients.Caller. -
SendMessageToGroupотправляет сообщение всем клиентам вSignalR Usersгруппе.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Строго типизированные центры
Недостаток использования SendAsync заключается в том, что он использует строку для указания вызываемого метода клиента. При этом код остается открытым для ошибок среды выполнения, если имя метода пропущено или отсутствует в клиенте.
Альтернативой использованию SendAsync является строго типизированный класс Hub с Hub<T>. В следующем примере метод ChatHub клиента был выделен в интерфейс под названием IChatClient.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Этот интерфейс можно использовать для рефакторинга предыдущего примера ChatHub, чтобы он стал строго типизированным.
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
Использование Hub<IChatClient> включает проверку времени компиляции клиентских методов. Это предотвращает проблемы, вызванные использованием строк, так как Hub<T> может предоставлять доступ только к методам, определенным в интерфейсе. Использование строго типизированного Hub<T> отключает возможность использования SendAsync.
Note
Суффикс Async не удаляется из имен методов. Если метод клиента не определен с помощью .on('MyMethodAsync'), не используйте MyMethodAsync в качестве имени.
Результаты клиента
Помимо вызова клиентов, сервер может запросить результат от клиента. Для этого требуется, чтобы сервер использовал ISingleClientProxy.InvokeAsync, а клиент возвращал результат от своего обработчика .On.
Существует два способа использования API на сервере, во-первых — вызов Client(...) или Caller на свойстве Clients в методе Hub.
public class ChatHub : Hub
{
public async Task<string> WaitForMessage(string connectionId)
{
var message = await Clients.Client(connectionId).InvokeAsync<string>(
"GetMessage");
return message;
}
}
Второй способ — вызвать Client(...) на экземпляре IHubContext<T>:
async Task SomeMethod(IHubContext<MyHub> context)
{
string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
"GetMessage");
}
Строго типизированные концентраторы также могут возвращать значения из методов интерфейса:
public interface IClient
{
Task<string> GetMessage();
}
public class ChatHub : Hub<IClient>
{
public async Task<string> WaitForMessage(string connectionId)
{
string message = await Clients.Client(connectionId).GetMessage();
return message;
}
}
Клиенты возвращают результаты в обработчиках .On(...), как показано ниже:
Клиент .NET
hubConnection.On("GetMessage", async () =>
{
Console.WriteLine("Enter message:");
var message = await Console.In.ReadLineAsync();
return message;
});
Клиент Typescript
hubConnection.on("GetMessage", async () => {
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("message");
}, 100);
});
return promise;
});
Клиент на Java
hubConnection.onWithResult("GetMessage", () -> {
return Single.just("message");
});
Изменение имени метода хаба
По умолчанию имя метода концентратора сервера — это имя метода .NET. Чтобы изменить это поведение по умолчанию для определенного метода, используйте атрибут HubMethodName . Клиент должен использовать это имя вместо имени метода .NET при вызове метода:
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Внедрение служб в концентратор
Конструкторы хабов могут принимать службы из системы внедрения зависимостей в виде параметров, которые можно хранить в свойства класса для использования в методах хаба.
При внедрении нескольких служб для различных методов хаба или как альтернативный способ написания кода, методы хаба также могут принимать службы из DI. По умолчанию параметры метода узла, если это возможно, проверяются и устраняются из DI.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message, IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Если не требуется неявное разрешение параметров из служб, отключите его с DisableImplicitFromServicesParameters.
Чтобы явно указать, какие параметры разрешаются из DI в методах концентратора, используйте опцию DisableImplicitFromServicesParameters и атрибут [FromServices] или настраиваемый атрибут, реализующий IFromServiceMetadata, на параметрах метода концентратора, которые должны разрешаться из DI.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message,
[FromServices] IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Note
Эта функция использует IServiceProviderIsService, который может быть реализован при необходимости реализациями DI. Если контейнер DI приложения не поддерживает эту функцию, внедрение служб в методы концентратора не поддерживается.
Обработка событий подключения
SignalR API системы Центров предоставляет OnConnectedAsync и OnDisconnectedAsync виртуальные методы для управления и отслеживания соединений. Переопределите виртуальный OnConnectedAsync метод для выполнения действий, когда клиент подключается к центру, например добавление его в группу:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Переопределите виртуальный OnDisconnectedAsync метод для выполнения действий при отключении клиента. Если клиент намеренно отключается, например путем вызова connection.stop(), exception параметр имеет значение null. Однако если клиент отключается из-за ошибки, например сбоя сети, exception параметр содержит исключение, описывающее сбой:
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync не нужно вызывать в OnDisconnectedAsync, это обрабатывается автоматически.
Управление ошибками
Исключения, возникающие в методах хабов, отправляются клиенту, который вызвал метод. В клиенте JavaScript метод invoke возвращает JavaScript Promise. Клиенты могут присоединить catch обработчик к возвращаемому обещанию или использовать try/catch для async/await обработки исключений.
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Подключения не закрываются, когда концентратор создает исключение. По умолчанию SignalR возвращается универсальное сообщение об ошибке клиенту, как показано в следующем примере:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.
Непредвиденные исключения часто содержат конфиденциальную информацию, например, имя сервера базы данных в случае, если соединение с базой данных прерывается. SignalR не предоставляет эти подробные сообщения об ошибках по умолчанию в качестве меры безопасности. Дополнительные сведения о том, почему сведения об исключении подавляются, см.: в разделе "Вопросы безопасности" в ASP.NET Core SignalR.
Если исключительное условие должно распространяться на клиент, используйте HubException класс.
HubException Если в методе концентратора создается исключение, SignalRотправляется клиенту все сообщение об исключении, не измененное:
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Note
SignalR отправляет клиенту только свойство Message исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
SignalR API Hubs позволяет подключенным клиентам вызывать методы на сервере, обеспечивая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. SignalR кроме того, обеспечивает непрямую связь между клиентами и клиентами, всегда опосредованную SignalR центром, позволяя отправлять сообщения между отдельными клиентами, группами или всеми подключенными клиентами. SignalR позаботится обо всем необходимом, чтобы обеспечить возможность обмена данными между клиентами и серверами в режиме реального времени.
Настройка SignalR центров
Чтобы зарегистрировать службы, необходимые для центров SignalR, вызовите AddSignalR в Program.cs.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Чтобы настроить SignalR конечные точки, вызовите MapHubтакже в Program.cs:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Note
Серверные сборки ASP.NET Core теперь устанавливаются с пакетом SDK для .NET Core. См. SignalR сборки в общем фреймворке для получения дополнительной информации.
Создание и использование центров
Создайте концентратор, объявив класс, наследуемый от Hub. Добавьте public методы в класс, чтобы сделать их вызываемыми из клиентов:
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
- Не сохраняйте состояние в свойстве класса концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр хаба непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext. - Используйте
awaitпри вызове асинхронных методов, которые зависят от поддержания работоспособности хаба. Например, методClients.All.SendAsync(...)может завершиться ошибкой, если его вызывают безawait, и метод концентратора завершается до завершенияSendAsync.
Объект Context
Класс Hub содержит Context свойство, содержащее следующие свойства со сведениями о подключении:
| Property | Description |
|---|---|
| ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
| UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR использует ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением в качестве идентификатора пользователя. |
| User | Возвращает ClaimsPrincipal, связанный с текущим пользователем. |
| Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
| Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
| ConnectionAborted | Получает CancellationToken, который уведомляет о прерывании подключения. |
Hub.Context также содержит следующие методы:
| Method | Description |
|---|---|
| GetHttpContext | Возвращает HttpContext для подключения или null, если подключение не связано с HTTP-запросом. Для HTTP-подключений используйте этот метод для получения таких сведений, как заголовки HTTP и строки запроса. |
| Abort | Прерывает подключение. |
Объект Client
Класс Hub содержит свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
| Property | Description |
|---|---|
| All | Вызывает метод для всех подключенных клиентов |
| Caller | Вызывает метод на клиенте, который вызвал метод хаба. |
| Others | Вызывает метод для всех подключенных клиентов, исключая клиента, который вызвал метод |
Hub.Clients также содержит следующие методы:
| Method | Description |
|---|---|
| AllExcept | Вызывает метод для всех подключенных клиентов, кроме указанных подключений. |
| Client | Вызывает метод для определенного подключенного клиента. |
| Clients | Вызывает метод для определенных подключенных клиентов |
| Group | Вызывает метод для всех подключений в указанной группе |
| GroupExcept | Вызывает метод для всех подключений в указанной группе, за исключением указанных подключений. |
| Groups | Вызывает метод для нескольких групп подключений |
| OthersInGroup | Вызывает метод в группе подключений, исключая клиента, который инициировал вызов метода узла. |
| User | Вызывает метод для всех подключений, связанных с конкретным пользователем |
| Users | Вызывает метод для всех подключений, связанных с указанными пользователями |
Каждое свойство или метод в предыдущих таблицах возвращает объект с методом SendAsync . Метод SendAsync получает имя метода клиента для вызова и любых параметров.
Отправка сообщений клиентам
Чтобы выполнить вызовы к определенным клиентам, используйте свойства Clients объекта. В следующем примере существуют три узловых метода:
-
SendMessageотправляет сообщение всем подключенным клиентам с помощьюClients.All. -
SendMessageToCallerотправляет сообщение обратно вызывающей стороне с помощьюClients.Caller. -
SendMessageToGroupотправляет сообщение всем клиентам вSignalR Usersгруппе.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Строго типизированные центры
Недостаток использования SendAsync заключается в том, что он использует строку для указания вызываемого метода клиента. При этом код остается открытым для ошибок среды выполнения, если имя метода пропущено или отсутствует в клиенте.
Альтернативой использованию SendAsync является строго типизированный класс Hub с Hub<T>. В следующем примере метод ChatHub клиента был выделен в интерфейс под названием IChatClient.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Этот интерфейс можно использовать для рефакторинга предыдущего примера ChatHub, чтобы он стал строго типизированным.
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
Использование Hub<IChatClient> включает проверку времени компиляции клиентских методов. Это предотвращает проблемы, вызванные использованием строк, так как Hub<T> может предоставлять доступ только к методам, определенным в интерфейсе. Использование строго типизированного Hub<T> отключает возможность использования SendAsync.
Note
Суффикс Async не удаляется из имен методов. Если метод клиента не определен с помощью .on('MyMethodAsync'), не используйте MyMethodAsync в качестве имени.
Изменение имени метода хаба
По умолчанию имя метода концентратора сервера — это имя метода .NET. Чтобы изменить это поведение по умолчанию для определенного метода, используйте атрибут HubMethodName . Клиент должен использовать это имя вместо имени метода .NET при вызове метода:
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Обработка событий подключения
SignalR API системы Центров предоставляет OnConnectedAsync и OnDisconnectedAsync виртуальные методы для управления и отслеживания соединений. Переопределите виртуальный OnConnectedAsync метод для выполнения действий, когда клиент подключается к центру, например добавление его в группу:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Переопределите виртуальный OnDisconnectedAsync метод для выполнения действий при отключении клиента. Если клиент намеренно отключается, например путем вызова connection.stop(), exception параметр имеет значение null. Однако если клиент отключается из-за ошибки, например сбоя сети, exception параметр содержит исключение, описывающее сбой:
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync не нужно вызывать в OnDisconnectedAsync, это обрабатывается автоматически.
Управление ошибками
Исключения, возникающие в методах хабов, отправляются клиенту, который вызвал метод. В клиенте JavaScript метод invoke возвращает JavaScript Promise. Клиенты могут присоединить catch обработчик к возвращаемому обещанию или использовать try/catch для async/await обработки исключений.
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Подключения не закрываются, когда концентратор создает исключение. По умолчанию SignalR возвращается универсальное сообщение об ошибке клиенту, как показано в следующем примере:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.
Непредвиденные исключения часто содержат конфиденциальную информацию, например, имя сервера базы данных в случае, если соединение с базой данных прерывается. SignalR не предоставляет эти подробные сообщения об ошибках по умолчанию в качестве меры безопасности. Дополнительные сведения о том, почему сведения об исключении подавляются, см.: в разделе "Вопросы безопасности" в ASP.NET Core SignalR.
Если исключительное условие должно распространяться на клиент, используйте HubException класс.
HubException Если в методе концентратора создается исключение, SignalRотправляется клиенту все сообщение об исключении, не измененное:
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Note
SignalR отправляет клиенту только свойство Message исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
Просмотреть или скачать образец кода (описание загрузки)
Что такое SignalR концентратор
SignalR API Hubs позволяет подключенным клиентам вызывать методы на сервере, обеспечивая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. SignalR кроме того, обеспечивает непрямую связь между клиентами и клиентами, всегда опосредованную SignalR центром, позволяя отправлять сообщения между отдельными клиентами, группами или всеми подключенными клиентами. SignalR позаботится обо всем необходимом, чтобы обеспечить возможность обмена данными между клиентами и серверами в режиме реального времени.
Настройка SignalR центров
Промежуточному ПО SignalR требуются некоторые службы, которые настраиваются путем вызова AddSignalR:
services.AddSignalR();
При добавлении SignalR функциональности в приложение ASP.NET Core настройте SignalR маршруты, вызвав MapHub в обратном вызове метода Startup.ConfigureUseEndpoints.
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chathub");
});
Note
Серверные сборки ASP.NET Core теперь устанавливаются с пакетом SDK для .NET Core. См. SignalR сборки в общем фреймворке для получения дополнительной информации.
Создание и использование центров
Создайте концентратор, объявив класс, наследуемый от Hub, и добавьте в него открытые методы. Клиенты могут вызывать методы, определенные как public:
public class ChatHub : Hub
{
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
Можно указать возвращаемый тип и параметры, включая сложные типы и массивы, как и в любом методе C#. SignalR обрабатывает сериализацию и десериализацию сложных объектов и массивов в параметрах и возвращаемых значениях.
Note
Центры являются временными:
- Не сохраняйте состояние в свойстве в классе концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр хаба непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext. - Используйте
awaitпри вызове асинхронных методов, которые зависят от поддержания работоспособности хаба. Например, методClients.All.SendAsync(...)может завершиться ошибкой, если его вызывают безawait, и метод концентратора завершается до завершенияSendAsync.
Объект Context
Класс Hub имеет Context свойство, содержащее следующие свойства со сведениями о подключении:
| Property | Description |
|---|---|
| ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
| UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR использует ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением в качестве идентификатора пользователя. |
| User | Возвращает ClaimsPrincipal, связанный с текущим пользователем. |
| Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
| Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
| ConnectionAborted | Получает CancellationToken, который уведомляет о прерывании подключения. |
Hub.Context также содержит следующие методы:
| Method | Description |
|---|---|
| GetHttpContext | Возвращает HttpContext для подключения или null, если подключение не связано с HTTP-запросом. Для HTTP-подключений этот метод можно использовать для получения таких сведений, как заголовки HTTP и строки запроса. |
| Abort | Прерывает подключение. |
Объект Client
Класс Hub имеет свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
| Property | Description |
|---|---|
| All | Вызывает метод для всех подключенных клиентов |
| Caller | Вызывает метод на клиенте, который вызвал метод хаба. |
| Others | Вызывает метод для всех подключенных клиентов, исключая клиента, который вызвал метод |
Hub.Clients также содержит следующие методы:
| Method | Description |
|---|---|
| AllExcept | Вызывает метод для всех подключенных клиентов, кроме указанных подключений. |
| Client | Вызывает метод для определенного подключенного клиента. |
| Clients | Вызывает метод для определенных подключенных клиентов |
| Group | Вызывает метод для всех подключений в указанной группе |
| GroupExcept | Вызывает метод для всех подключений в указанной группе, за исключением указанных подключений. |
| Groups | Вызывает метод для нескольких групп подключений |
| OthersInGroup | Вызывает метод в группе подключений, исключая клиента, который инициировал вызов метода узла. |
| User | Вызывает метод для всех подключений, связанных с конкретным пользователем |
| Users | Вызывает метод для всех подключений, связанных с указанными пользователями |
Каждое свойство или метод в предыдущих таблицах возвращает объект с методом SendAsync . Этот SendAsync метод позволяет указать имя и параметры вызываемого метода клиента.
Отправка сообщений клиентам
Чтобы выполнить вызовы к определенным клиентам, используйте свойства Clients объекта. В следующем примере есть три метода Hub:
-
SendMessageотправляет сообщение всем подключенным клиентам с помощьюClients.All. -
SendMessageToCallerотправляет сообщение обратно вызывающей стороне с помощьюClients.Caller. -
SendMessageToGroupотправляет сообщение всем клиентам вSignalR Usersгруппе.
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToGroup(string user, string message)
{
return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}
Строго типизированные центры
Недостаток использования SendAsync заключается в том, что он использует магическую строку для указания вызываемого метода клиента. При этом код остается открытым для ошибок среды выполнения, если имя метода пропущено или отсутствует в клиенте.
Альтернативой использованию SendAsync является строгая типизация Hub с помощью Hub<T>. В следующем примере методы ChatHub клиента были извлечены в интерфейс под названием IChatClient.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Этот интерфейс можно использовать для рефакторинга предыдущего ChatHub примера:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.ReceiveMessage(user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.ReceiveMessage(user, message);
}
}
Использование Hub<IChatClient> включает проверку времени компиляции клиентских методов. Это предотвращает проблемы, вызванные использованием магических строк, так как Hub<T> может предоставлять доступ только к методам, определенным в интерфейсе.
Использование строго типизированного Hub<T> отключает возможность использования SendAsync. Все методы, определенные в интерфейсе, по-прежнему могут быть определены как асинхронные. На самом деле, каждый из этих методов должен возвращать Task. Так как это интерфейс, не используйте ключевое async слово. Рассмотрим пример.
public interface IClient
{
Task ClientMethod();
}
Note
Суффикс Async не удаляется из имени метода. Если метод клиента не определен с помощью .on('MyMethodAsync'), вам не следует использовать MyMethodAsync в качестве имени.
Изменение имени метода хаба
По умолчанию имя метода концентратора сервера — это имя метода .NET. Однако атрибут HubMethodName можно использовать для изменения этого значения по умолчанию и вручную указать имя метода. Клиент должен использовать это имя вместо имени метода .NET при вызове метода:
[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}
Обработка событий подключения
SignalR API системы Центров предоставляет OnConnectedAsync и OnDisconnectedAsync виртуальные методы для управления и отслеживания соединений. Переопределите виртуальный OnConnectedAsync метод для выполнения действий, когда клиент подключается к Центру, например добавление его в группу:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Переопределите виртуальный OnDisconnectedAsync метод для выполнения действий при отключении клиента. Если клиент намеренно отключается (например, вызывая connection.stop()), параметр exception станет null. Однако если клиент отключен из-за ошибки (например, сбой сети), exception параметр будет содержать исключение, описывающее сбой:
public override async Task OnDisconnectedAsync(Exception exception)
{
await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync не нужно вызывать в OnDisconnectedAsync, это обрабатывается автоматически.
Warning
Предупреждение безопасности: предоставление ConnectionId доступа может привести к вредоносному олицетворению, если SignalR сервер или версия клиента ASP.NET Core 2.2 или более ранней.
Управление ошибками
Исключения, возникающие в методах хаба, отправляются клиенту, который вызвал метод. В клиенте JavaScript метод invoke возвращает JavaScript Promise. Когда клиент получает ошибку с обработчиком, прикрепленным к обещанию, обработчик catch вызывается и ему передается объект JavaScript Error.
connection.invoke("SendMessage", user, message).catch(err => console.error(err));
Если центр создает исключение, подключения не закрываются. По умолчанию SignalR возвращается универсальное сообщение об ошибке клиенту. Рассмотрим пример.
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.
Непредвиденные исключения часто содержат конфиденциальную информацию, например, имя сервера базы данных в случае, если соединение с базой данных прерывается. SignalR не предоставляет эти подробные сообщения об ошибках по умолчанию в качестве меры безопасности. Дополнительные сведения о том, почему сведения об исключении подавляются, см.: в разделе "Вопросы безопасности" в ASP.NET Core SignalR.
Если у вас есть исключительное условие, которое вы хотите распространить на клиент, можно использовать HubException класс. Если вы выбрасываете HubException из метода концентратора, SignalRотправит неизменённое сообщение клиенту:
public Task ThrowException()
{
throw new HubException("This error will be sent to the client!");
}
Note
SignalR отправляет клиенту только свойство Message исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
Просмотреть или скачать образец кода (описание загрузки)
Что такое SignalR концентратор
SignalR API Hubs позволяет подключенным клиентам вызывать методы на сервере, обеспечивая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. SignalR кроме того, обеспечивает непрямую связь между клиентами и клиентами, всегда опосредованную SignalR центром, позволяя отправлять сообщения между отдельными клиентами, группами или всеми подключенными клиентами. SignalR позаботится обо всем необходимом, чтобы обеспечить возможность обмена данными между клиентами и серверами в режиме реального времени.
Настройка SignalR центров
Промежуточному ПО SignalR требуются некоторые службы, которые настраиваются путем вызова AddSignalR:
services.AddSignalR();
При добавлении SignalR функциональности в приложение ASP.NET Core настройте SignalR маршруты, вызвав UseSignalR в методе Startup.Configure:
app.UseSignalR(route =>
{
route.MapHub<ChatHub>("/chathub");
});
Создание и использование центров
Создайте концентратор, объявив класс, наследуемый от Hub, и добавьте в него открытые методы. Клиенты могут вызывать методы, определенные как public:
public class ChatHub : Hub
{
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
Можно указать возвращаемый тип и параметры, включая сложные типы и массивы, как и в любом методе C#. SignalR обрабатывает сериализацию и десериализацию сложных объектов и массивов в параметрах и возвращаемых значениях.
Note
Центры являются временными:
- Не сохраняйте состояние в свойстве в классе концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр хаба непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext. - Используйте
awaitпри вызове асинхронных методов, которые зависят от поддержания работоспособности хаба. Например, методClients.All.SendAsync(...)может завершиться ошибкой, если его вызывают безawait, и метод концентратора завершается до завершенияSendAsync.
Объект Context
Класс Hub имеет Context свойство, содержащее следующие свойства со сведениями о подключении:
| Property | Description |
|---|---|
| ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
| UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR использует ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением в качестве идентификатора пользователя. |
| User | Возвращает ClaimsPrincipal, связанный с текущим пользователем. |
| Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
| Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
| ConnectionAborted | Получает CancellationToken, который уведомляет о прерывании подключения. |
Hub.Context также содержит следующие методы:
| Method | Description |
|---|---|
| GetHttpContext | Возвращает HttpContext для подключения или null, если подключение не связано с HTTP-запросом. Для HTTP-подключений этот метод можно использовать для получения таких сведений, как заголовки HTTP и строки запроса. |
| Abort | Прерывает подключение. |
Объект Client
Класс Hub имеет свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
| Property | Description |
|---|---|
| All | Вызывает метод для всех подключенных клиентов |
| Caller | Вызывает метод на клиенте, который вызвал метод хаба. |
| Others | Вызывает метод для всех подключенных клиентов, исключая клиента, который вызвал метод |
Hub.Clients также содержит следующие методы:
| Method | Description |
|---|---|
| AllExcept | Вызывает метод для всех подключенных клиентов, кроме указанных подключений. |
| Client | Вызывает метод для определенного подключенного клиента. |
| Clients | Вызывает метод для определенных подключенных клиентов |
| Group | Вызывает метод для всех подключений в указанной группе |
| GroupExcept | Вызывает метод для всех подключений в указанной группе, за исключением указанных подключений. |
| Groups | Вызывает метод для нескольких групп подключений |
| OthersInGroup | Вызывает метод в группе подключений, исключая клиента, который инициировал вызов метода узла. |
| User | Вызывает метод для всех подключений, связанных с конкретным пользователем |
| Users | Вызывает метод для всех подключений, связанных с указанными пользователями |
Каждое свойство или метод в предыдущих таблицах возвращает объект с методом SendAsync . Этот SendAsync метод позволяет указать имя и параметры вызываемого метода клиента.
Отправка сообщений клиентам
Чтобы выполнить вызовы к определенным клиентам, используйте свойства Clients объекта. В следующем примере есть три метода Hub:
-
SendMessageотправляет сообщение всем подключенным клиентам с помощьюClients.All. -
SendMessageToCallerотправляет сообщение обратно вызывающей стороне с помощьюClients.Caller. -
SendMessageToGroupотправляет сообщение всем клиентам вSignalR Usersгруппе.
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToGroup(string user, string message)
{
return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}
Строго типизированные центры
Недостаток использования SendAsync заключается в том, что он использует магическую строку для указания вызываемого метода клиента. При этом код остается открытым для ошибок среды выполнения, если имя метода пропущено или отсутствует в клиенте.
Альтернативой использованию SendAsync является строгая типизация Hub с помощью Hub<T>. В следующем примере методы ChatHub клиента были извлечены в интерфейс под названием IChatClient.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Этот интерфейс можно использовать для рефакторинга предыдущего ChatHub примера:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.ReceiveMessage(user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.ReceiveMessage(user, message);
}
}
Использование Hub<IChatClient> включает проверку времени компиляции клиентских методов. Это предотвращает проблемы, вызванные использованием магических строк, так как Hub<T> может предоставлять доступ только к методам, определенным в интерфейсе.
Использование строго типизированного Hub<T> отключает возможность использования SendAsync. Все методы, определенные в интерфейсе, по-прежнему могут быть определены как асинхронные. На самом деле, каждый из этих методов должен возвращать Task. Так как это интерфейс, не используйте ключевое async слово. Рассмотрим пример.
public interface IClient
{
Task ClientMethod();
}
Note
Суффикс Async не удаляется из имени метода. Если метод клиента не определен с помощью .on('MyMethodAsync'), вам не следует использовать MyMethodAsync в качестве имени.
Изменение имени метода хаба
По умолчанию имя метода концентратора сервера — это имя метода .NET. Однако атрибут HubMethodName можно использовать для изменения этого значения по умолчанию и вручную указать имя метода. Клиент должен использовать это имя вместо имени метода .NET при вызове метода:
[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}
Обработка событий подключения
SignalR API системы Центров предоставляет OnConnectedAsync и OnDisconnectedAsync виртуальные методы для управления и отслеживания соединений. Переопределите виртуальный OnConnectedAsync метод для выполнения действий, когда клиент подключается к Центру, например добавление его в группу:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Переопределите виртуальный OnDisconnectedAsync метод для выполнения действий при отключении клиента. Если клиент намеренно отключается (например, вызывая connection.stop()), параметр exception станет null. Однако если клиент отключен из-за ошибки (например, сбой сети), exception параметр будет содержать исключение, описывающее сбой:
public override async Task OnDisconnectedAsync(Exception exception)
{
await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync не нужно вызывать в OnDisconnectedAsync, это обрабатывается автоматически.
Warning
Предупреждение безопасности: предоставление ConnectionId доступа может привести к вредоносному олицетворению, если SignalR сервер или версия клиента ASP.NET Core 2.2 или более ранней.
Управление ошибками
Исключения, возникающие в методах хаба, отправляются клиенту, который вызвал метод. В клиенте JavaScript метод invoke возвращает JavaScript Promise. Когда клиент получает ошибку с обработчиком, прикрепленным к обещанию, обработчик catch вызывается и ему передается объект JavaScript Error.
connection.invoke("SendMessage", user, message).catch(err => console.error(err));
Если центр создает исключение, подключения не закрываются. По умолчанию SignalR возвращается универсальное сообщение об ошибке клиенту. Рассмотрим пример.
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.
Непредвиденные исключения часто содержат конфиденциальную информацию, например, имя сервера базы данных в случае, если соединение с базой данных прерывается. SignalR не предоставляет эти подробные сообщения об ошибках по умолчанию в качестве меры безопасности. Дополнительные сведения о том, почему сведения об исключении подавляются, см.: в разделе "Вопросы безопасности" в ASP.NET Core SignalR.
Если у вас есть исключительное условие, которое вы хотите распространить на клиент, можно использовать HubException класс. Если вы выбрасываете HubException из метода концентратора, SignalRотправит неизменённое сообщение клиенту:
public Task ThrowException()
{
throw new HubException("This error will be sent to the client!");
}
Note
SignalR отправляет клиенту только свойство Message исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
ASP.NET Core