Использование центров SignalR для ASP.NET Core
SignalR API Центров позволяет подключенным клиентам вызывать методы на сервере, упрощая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. 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();
Примечание.
ASP.NET сборки на SignalR стороне сервера теперь устанавливаются с помощью пакета 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);
}
Примечание.
- Не сохраняйте состояние в свойстве класса концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр концентратора непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext
. - Используйте
await
при вызове асинхронных методов, зависящих от центра, оставающегося в живых. Например, метод, напримерClients.All.SendAsync(...)
, может завершиться ошибкой, если он вызывается без вызоваawait
, а метод концентратора завершается доSendAsync
завершения.
Объект Context
Класс Hub содержит Context свойство, содержащее следующие свойства со сведениями о подключении:
Свойство | Description |
---|---|
ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR в качестве идентификатора пользователя используется ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением. |
User | Возвращает связанный ClaimsPrincipal с текущим пользователем. |
Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
ConnectionAborted | CancellationToken Возвращает уведомление о прерывании подключения. |
Hub.Context также содержит следующие методы:
Метод | Description |
---|---|
GetHttpContext | HttpContext Возвращает значение для подключения или null если подключение не связано с HTTP-запросом. Для HTTP-подключений используйте этот метод для получения таких сведений, как заголовки HTTP и строки запроса. |
Abort | Прерывает подключение. |
Объект Client
Класс Hub содержит свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
Свойство | Description |
---|---|
All | Вызывает метод для всех подключенных клиентов |
Caller | Вызывает метод на клиенте, который вызвал метод концентратора. |
Others | Вызывает метод для всех подключенных клиентов, кроме клиента, вызвавого метод |
Hub.Clients также содержит следующие методы:
Метод | 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
.
Примечание.
Суффикс 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);
}
}
Примечание.
Эта функция использует IServiceProviderIsService, которая при необходимости реализуется реализацией DI. Если контейнер DI приложения не поддерживает эту функцию, внедрение служб в методы концентратора не поддерживается.
Поддержка ключевых служб в внедрении зависимостей
Ключи служб относятся к механизму регистрации и получения служб внедрения зависимостей (DI) с помощью ключей. Служба связана с ключом путем вызова AddKeyedSingleton (или AddKeyedScoped
AddKeyedTransient
) для регистрации. Доступ к зарегистрированной службе путем указания ключа с атрибутом [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вызывать его, он автоматически обрабатывается для вас.
Обработка ошибок
Исключения, возникающие в методах концентратора, отправляются клиенту, который вызвал метод. В клиенте invoke
JavaScript метод возвращает JavaScript Promise
. Клиенты могут присоединить catch
обработчик к возвращаемого обещания или использовать/catch
try
для 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!");
Примечание.
SignalR отправляет Message
клиенту только свойство исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
SignalR API Центров позволяет подключенным клиентам вызывать методы на сервере, упрощая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. 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();
Примечание.
ASP.NET сборки на SignalR стороне сервера теперь устанавливаются с помощью пакета 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);
}
Примечание.
- Не сохраняйте состояние в свойстве класса концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр концентратора непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext
. - Используйте
await
при вызове асинхронных методов, зависящих от центра, оставающегося в живых. Например, метод, напримерClients.All.SendAsync(...)
, может завершиться ошибкой, если он вызывается без вызоваawait
, а метод концентратора завершается доSendAsync
завершения.
Объект Context
Класс Hub содержит Context свойство, содержащее следующие свойства со сведениями о подключении:
Свойство | Description |
---|---|
ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR в качестве идентификатора пользователя используется ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением. |
User | Возвращает связанный ClaimsPrincipal с текущим пользователем. |
Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
ConnectionAborted | CancellationToken Возвращает уведомление о прерывании подключения. |
Hub.Context также содержит следующие методы:
Метод | Description |
---|---|
GetHttpContext | HttpContext Возвращает значение для подключения или null если подключение не связано с HTTP-запросом. Для HTTP-подключений используйте этот метод для получения таких сведений, как заголовки HTTP и строки запроса. |
Abort | Прерывает подключение. |
Объект Client
Класс Hub содержит свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
Свойство | Description |
---|---|
All | Вызывает метод для всех подключенных клиентов |
Caller | Вызывает метод на клиенте, который вызвал метод концентратора. |
Others | Вызывает метод для всех подключенных клиентов, кроме клиента, вызвавого метод |
Hub.Clients также содержит следующие методы:
Метод | 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
.
Примечание.
Суффикс 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);
}
}
Примечание.
Эта функция использует 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вызывать его, он автоматически обрабатывается для вас.
Обработка ошибок
Исключения, возникающие в методах концентратора, отправляются клиенту, который вызвал метод. В клиенте invoke
JavaScript метод возвращает JavaScript Promise
. Клиенты могут присоединить catch
обработчик к возвращаемого обещания или использовать/catch
try
для 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!");
Примечание.
SignalR отправляет Message
клиенту только свойство исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
SignalR API Центров позволяет подключенным клиентам вызывать методы на сервере, упрощая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. 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();
Примечание.
ASP.NET сборки на SignalR стороне сервера теперь устанавливаются с помощью пакета 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);
}
Примечание.
- Не сохраняйте состояние в свойстве класса концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр концентратора непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext
. - Используйте
await
при вызове асинхронных методов, зависящих от центра, оставающегося в живых. Например, метод, напримерClients.All.SendAsync(...)
, может завершиться ошибкой, если он вызывается без вызоваawait
, а метод концентратора завершается доSendAsync
завершения.
Объект Context
Класс Hub содержит Context свойство, содержащее следующие свойства со сведениями о подключении:
Свойство | Description |
---|---|
ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR в качестве идентификатора пользователя используется ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением. |
User | Возвращает связанный ClaimsPrincipal с текущим пользователем. |
Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
ConnectionAborted | CancellationToken Возвращает уведомление о прерывании подключения. |
Hub.Context также содержит следующие методы:
Метод | Description |
---|---|
GetHttpContext | HttpContext Возвращает значение для подключения или null если подключение не связано с HTTP-запросом. Для HTTP-подключений используйте этот метод для получения таких сведений, как заголовки HTTP и строки запроса. |
Abort | Прерывает подключение. |
Объект Client
Класс Hub содержит свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
Свойство | Description |
---|---|
All | Вызывает метод для всех подключенных клиентов |
Caller | Вызывает метод на клиенте, который вызвал метод концентратора. |
Others | Вызывает метод для всех подключенных клиентов, кроме клиента, вызвавого метод |
Hub.Clients также содержит следующие методы:
Метод | 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
.
Примечание.
Суффикс 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вызывать его, он автоматически обрабатывается для вас.
Обработка ошибок
Исключения, возникающие в методах концентратора, отправляются клиенту, который вызвал метод. В клиенте invoke
JavaScript метод возвращает JavaScript Promise
. Клиенты могут присоединить catch
обработчик к возвращаемого обещания или использовать/catch
try
для 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!");
Примечание.
SignalR отправляет Message
клиенту только свойство исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
Просмотреть или скачать образец кода (описание загрузки)
Что такое SignalR концентратор
SignalR API Центров позволяет подключенным клиентам вызывать методы на сервере, упрощая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. SignalR кроме того, обеспечивает непрямую связь между клиентами и клиентами, всегда опосредованную SignalR центром, позволяя отправлять сообщения между отдельными клиентами, группами или всеми подключенными клиентами. SignalR все необходимое для обеспечения возможности обмена данными между клиентами и серверами в режиме реального времени.
Настройка SignalR центров
По промежуточному SignalR слоям требуются некоторые службы, настроенные путем вызова AddSignalR:
services.AddSignalR();
При добавлении SignalR функций в приложение ASP.NET Core настройте SignalR маршруты путем вызова обратного Startup.Configure
вызова MapHub методаUseEndpoints:
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chathub");
});
Примечание.
ASP.NET сборки на SignalR стороне сервера теперь устанавливаются с помощью пакета 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 обрабатывает сериализацию и десериализацию сложных объектов и массивов в параметрах и возвращаемых значениях.
Примечание.
Центры являются временными:
- Не сохраняйте состояние в свойстве в классе концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр концентратора непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext
. - Используйте
await
при вызове асинхронных методов, зависящих от центра, оставающегося в живых. Например, метод, напримерClients.All.SendAsync(...)
, может завершиться ошибкой, если он вызывается без вызоваawait
, а метод концентратора завершается доSendAsync
завершения.
Объект Context
Класс Hub имеет Context свойство, содержащее следующие свойства со сведениями о подключении:
Свойство | Description |
---|---|
ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR в качестве идентификатора пользователя используется ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением. |
User | Возвращает связанный ClaimsPrincipal с текущим пользователем. |
Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
ConnectionAborted | CancellationToken Возвращает уведомление о прерывании подключения. |
Hub.Context также содержит следующие методы:
Метод | Description |
---|---|
GetHttpContext | HttpContext Возвращает значение для подключения или null если подключение не связано с HTTP-запросом. Для HTTP-подключений этот метод можно использовать для получения таких сведений, как заголовки HTTP и строки запроса. |
Abort | Прерывает подключение. |
Объект Client
Класс Hub имеет свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
Свойство | Description |
---|---|
All | Вызывает метод для всех подключенных клиентов |
Caller | Вызывает метод на клиенте, который вызвал метод концентратора. |
Others | Вызывает метод для всех подключенных клиентов, кроме клиента, вызвавого метод |
Hub.Clients также содержит следующие методы:
Метод | Description |
---|---|
AllExcept | Вызывает метод для всех подключенных клиентов, кроме указанных подключений. |
Client | Вызывает метод для определенного подключенного клиента. |
Clients | Вызывает метод для определенных подключенных клиентов |
Group | Вызывает метод для всех подключений в указанной группе |
GroupExcept | Вызывает метод для всех подключений в указанной группе, за исключением указанных подключений. |
Groups | Вызывает метод для нескольких групп подключений |
OthersInGroup | Вызывает метод в группе подключений, за исключением клиента, вызывающего метод концентратора. |
User | Вызывает метод для всех подключений, связанных с конкретным пользователем |
Users | Вызывает метод для всех подключений, связанных с указанными пользователями |
Каждое свойство или метод в предыдущих таблицах возвращает объект с методом SendAsync
. Этот SendAsync
метод позволяет указать имя и параметры вызываемого метода клиента.
Отправка сообщений клиентам
Чтобы выполнить вызовы к определенным клиентам, используйте свойства Clients
объекта. В следующем примере существует три метода Концентратора:
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();
}
Примечание.
Суффикс 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вызывать его, он автоматически обрабатывается для вас.
Предупреждение
Предупреждение системы безопасности. Предоставление ConnectionId
доступа может привести к вредоносной олицетворении, если SignalR сервер или версия клиента ASP.NET Core 2.2 или более ранней версии.
Обработка ошибок
Исключения, возникающие в методах концентратора, отправляются клиенту, который вызвал метод. В клиенте invoke
JavaScript метод возвращает 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!");
}
Примечание.
SignalR отправляет Message
клиенту только свойство исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
Просмотреть или скачать образец кода (описание загрузки)
Что такое SignalR концентратор
SignalR API Центров позволяет подключенным клиентам вызывать методы на сервере, упрощая обмен данными в режиме реального времени. Сервер определяет методы, вызываемые клиентом, и клиент определяет методы, вызываемые сервером. 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 обрабатывает сериализацию и десериализацию сложных объектов и массивов в параметрах и возвращаемых значениях.
Примечание.
Центры являются временными:
- Не сохраняйте состояние в свойстве в классе концентратора. Каждый вызов метода концентратора выполняется в новом экземпляре концентратора.
- Не создавайте экземпляр концентратора непосредственно с помощью внедрения зависимостей. Для отправки сообщений клиенту из другого места в приложении используется
IHubContext
. - Используйте
await
при вызове асинхронных методов, зависящих от центра, оставающегося в живых. Например, метод, напримерClients.All.SendAsync(...)
, может завершиться ошибкой, если он вызывается без вызоваawait
, а метод концентратора завершается доSendAsync
завершения.
Объект Context
Класс Hub имеет Context свойство, содержащее следующие свойства со сведениями о подключении:
Свойство | Description |
---|---|
ConnectionId | Возвращает уникальный идентификатор подключения, назначенный SignalR. Для каждого подключения существует один идентификатор подключения. |
UserIdentifier | Возвращает идентификатор пользователя. По умолчанию SignalR в качестве идентификатора пользователя используется ClaimTypes.NameIdentifier из ClaimsPrincipal связанного с подключением. |
User | Возвращает связанный ClaimsPrincipal с текущим пользователем. |
Items | Возвращает коллекцию ключей и значений, которую можно использовать для совместного использования данных в области этого подключения. Данные можно хранить в этой коллекции, и они будут сохраняться для подключения между различными вызовами методов концентратора. |
Features | Возвращает коллекцию функций, доступных в соединении. Сейчас эта коллекция не требуется в большинстве сценариев, поэтому она еще не описана. |
ConnectionAborted | CancellationToken Возвращает уведомление о прерывании подключения. |
Hub.Context также содержит следующие методы:
Метод | Description |
---|---|
GetHttpContext | HttpContext Возвращает значение для подключения или null если подключение не связано с HTTP-запросом. Для HTTP-подключений этот метод можно использовать для получения таких сведений, как заголовки HTTP и строки запроса. |
Abort | Прерывает подключение. |
Объект Client
Класс Hub имеет свойство, содержащее следующие свойства для обмена данными между сервером Clients и клиентом:
Свойство | Description |
---|---|
All | Вызывает метод для всех подключенных клиентов |
Caller | Вызывает метод на клиенте, который вызвал метод концентратора. |
Others | Вызывает метод для всех подключенных клиентов, кроме клиента, вызвавого метод |
Hub.Clients также содержит следующие методы:
Метод | Description |
---|---|
AllExcept | Вызывает метод для всех подключенных клиентов, кроме указанных подключений. |
Client | Вызывает метод для определенного подключенного клиента. |
Clients | Вызывает метод для определенных подключенных клиентов |
Group | Вызывает метод для всех подключений в указанной группе |
GroupExcept | Вызывает метод для всех подключений в указанной группе, за исключением указанных подключений. |
Groups | Вызывает метод для нескольких групп подключений |
OthersInGroup | Вызывает метод в группе подключений, за исключением клиента, вызывающего метод концентратора. |
User | Вызывает метод для всех подключений, связанных с конкретным пользователем |
Users | Вызывает метод для всех подключений, связанных с указанными пользователями |
Каждое свойство или метод в предыдущих таблицах возвращает объект с методом SendAsync
. Этот SendAsync
метод позволяет указать имя и параметры вызываемого метода клиента.
Отправка сообщений клиентам
Чтобы выполнить вызовы к определенным клиентам, используйте свойства Clients
объекта. В следующем примере существует три метода Концентратора:
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();
}
Примечание.
Суффикс 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вызывать его, он автоматически обрабатывается для вас.
Предупреждение
Предупреждение системы безопасности. Предоставление ConnectionId
доступа может привести к вредоносной олицетворении, если SignalR сервер или версия клиента ASP.NET Core 2.2 или более ранней версии.
Обработка ошибок
Исключения, возникающие в методах концентратора, отправляются клиенту, который вызвал метод. В клиенте invoke
JavaScript метод возвращает 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!");
}
Примечание.
SignalR отправляет Message
клиенту только свойство исключения. Трассировка стека и другие свойства исключения недоступны клиенту.
Дополнительные ресурсы
ASP.NET Core