Поделиться через


Использование центров 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 клиенту только свойство исключения. Трассировка стека и другие свойства исключения недоступны клиенту.

Дополнительные ресурсы