Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Клиентская библиотека .NET для ASP.NET Core SignalR позволяет приложениям .NET взаимодействовать с концентраторами SignalR. В этой статье описывается, как использовать API для подключения к концентратору SignalR и вызывать методы центра и клиента .NET. Пример кода в этой статье — это приложение Windows Presentation Foundation (WPF), использующее клиент ASP.NET Core SignalR .NET.
Просмотреть или скачать образец кода (описание загрузки)
Установка клиентского SignalR пакета .NET
Для подключения клиентов .NET к хабам SignalR требуется пакет Microsoft.AspNetCore.SignalR.Client. Клиентская библиотека можно установить из консоли Visual Studio диспетчер пакетов или с помощью интерфейса командной строки .NET.
Выполните следующую команду в окне диспетчер пакетов console:
Install-Package Microsoft.AspNetCore.SignalR.Client
Подключение к концентратору
Чтобы установить соединение, создайте HubConnectionBuilder и вызовите Build. URL-адрес концентратора, протокол, тип транспорта, уровень журнала, заголовки и другие параметры можно настроить при создании подключения. Настройте все необходимые параметры, вставив любой из методов HubConnectionBuilder в Build. Запустите подключение с StartAsync.
using System;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.AspNetCore.SignalR.Client;
namespace SignalRChatClient
{
public partial class MainWindow : Window
{
HubConnection connection;
public MainWindow()
{
InitializeComponent();
connection = new HubConnectionBuilder()
.WithUrl("http://localhost:53353/ChatHub")
.Build();
connection.Closed += async (error) =>
{
await Task.Delay(new Random().Next(0,5) * 1000);
await connection.StartAsync();
};
}
private async void connectButton_Click(object sender, RoutedEventArgs e)
{
connection.On<string, string>("ReceiveMessage", (user, message) =>
{
this.Dispatcher.Invoke(() =>
{
var newMessage = $"{user}: {message}";
messagesList.Items.Add(newMessage);
});
});
try
{
await connection.StartAsync();
messagesList.Items.Add("Connection started");
connectButton.IsEnabled = false;
sendButton.IsEnabled = true;
}
catch (Exception ex)
{
messagesList.Items.Add(ex.Message);
}
}
private async void sendButton_Click(object sender, RoutedEventArgs e)
{
try
{
await connection.InvokeAsync("SendMessage",
userTextBox.Text, messageTextBox.Text);
}
catch (Exception ex)
{
messagesList.Items.Add(ex.Message);
}
}
}
}
Обработка потерянного соединения
Чтобы повторно подключиться к клиентам, можно настроить автоматическое повторное подключение или настроить повторное подключение вручную.
Автоматическое повторное подключение
HubConnection можно настроить для автоматического повторного подключения с помощью метода WithAutomaticReconnect объекта HubConnectionBuilder. По умолчанию он не выполняет автоматическое повторное подключение.
HubConnection connection= new HubConnectionBuilder()
.WithUrl(new Uri("http://127.0.0.1:5000/chathub"))
.WithAutomaticReconnect()
.Build();
Без каких-либо параметров WithAutomaticReconnect() клиент настраивает ожидание 0, 2, 10 и 30 секунд соответственно перед попыткой повторного подключения. Он останавливается после четырех неудачных попыток.
Перед началом любых попыток повторного подключения HubConnection переходит в состояние HubConnectionState.Reconnecting и генерирует событие Reconnecting. Этот подход позволяет предупреждать пользователей о том, что подключение потеряно и отключает элементы пользовательского интерфейса. Неинтерактивные приложения могут начать ставить сообщения в очередь или отбрасывать их.
connection.Reconnecting += error =>
{
Debug.Assert(connection.State == HubConnectionState.Reconnecting);
// Notify users the connection was lost and the client is reconnecting.
// Start queuing or dropping messages.
return Task.CompletedTask;
};
Если клиент успешно переподключается в течение первых четырёх попыток, HubConnection снова переходит в состояние Connected и инициирует событие Reconnected. Этот подход позволяет информировать пользователей о том, что подключение теперь восстановлено, и вывести из очереди сообщения.
Поскольку соединение выглядит для сервера как совершенно новое, обработчикам события Reconnected передаётся новый ConnectionId.
Warning
Параметр connectionId обработчика события Reconnected имеет значение null, если HubConnection настроен на пропуск согласования.
connection.Reconnected += connectionId =>
{
Debug.Assert(connection.State == HubConnectionState.Connected);
// Notify users the connection was reestablished.
// Start dequeuing messages queued while reconnecting if any.
return Task.CompletedTask;
};
WithAutomaticReconnect() не настраивает HubConnection на повторные попытки при сбоях первоначального запуска, поэтому такие сбои необходимо обрабатывать вручную:
public static async Task<bool> ConnectWithRetryAsync(HubConnection connection, CancellationToken token)
{
// Keep trying to until we can start or the token is canceled.
while (true)
{
try
{
await connection.StartAsync(token);
Debug.Assert(connection.State == HubConnectionState.Connected);
return true;
}
catch when (token.IsCancellationRequested)
{
return false;
}
catch
{
// Failed to connect, trying again in 5000 ms.
Debug.Assert(connection.State == HubConnectionState.Disconnected);
await Task.Delay(5000);
}
}
}
Если клиенту не удаётся успешно переподключиться в течение первых четырёх попыток, HubConnection переходит в состояние Disconnected и вызывает событие Closed. Этот подход предоставляет возможность повторно перезапустить подключение вручную или сообщить пользователям, что подключение теперь окончательно потеряно.
connection.Closed += error =>
{
Debug.Assert(connection.State == HubConnectionState.Disconnected);
// Notify users the connection has been closed or manually try to restart the connection.
return Task.CompletedTask;
};
Чтобы настроить настраиваемое количество попыток повторного подключения перед отключением или изменением времени повторного подключения, WithAutomaticReconnect принимает массив чисел, представляющих задержку в миллисекундах, чтобы ждать перед началом каждой попытки повторного подключения.
HubConnection connection = new HubConnectionBuilder()
.WithUrl(new Uri("http://127.0.0.1:5000/chathub"))
.WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(10) })
.Build();
// .WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(30) }) yields the default behavior.
В предыдущем примере HubConnection настраивается так, чтобы он начинал пытаться выполнять повторные подключения сразу после потери соединения. Этот подход также относится к конфигурации по умолчанию.
Если первая попытка повторного подключения завершается ошибкой, вторая попытка повторного подключения также запускается немедленно, а не ожидает 2 секунд, как определено в конфигурации по умолчанию.
Если вторая попытка повторного подключения завершается сбоем, третья попытка повторного подключения начинается в 10 секунд, то это то же поведение, определенное в конфигурации по умолчанию.
Пользовательское поведение затем снова отличается от поведения по умолчанию тем, что прекращается после третьей неудачной попытки переподключения. В конфигурации по умолчанию выполняется еще одна попытка повторного подключения через 30 секунд.
Для получения большего контроля над временем и количеством попыток WithAutomaticReconnect автоматического повторного подключения принимает объект, реализующий IRetryPolicy интерфейс, имеющий один метод с именем NextRetryDelay.
NextRetryDelay принимает один аргумент с типом RetryContext. Имеет RetryContext три свойства: PreviousRetryCount (тип), long (типElapsedTimeTimeSpan) и RetryReason (типException).
Перед первой попыткой повторного подключения и
PreviousRetryCount, иElapsedTimeравны нулю (0), аRetryReason— это исключение, вызвавшее потерю соединения.После каждой неудачной повторной попытки
PreviousRetryCountувеличивается на единицу,ElapsedTimeобновляется, чтобы отразить время, затраченное на повторное подключение к текущему моменту, аRetryReason— это исключение, из-за которого последняя попытка повторного подключения завершилась ошибкой.
NextRetryDelay должен возвращать значение TimeSpan , представляющее время ожидания перед следующей попыткой повторного подключения или nullHubConnection если необходимо остановить повторное подключение.
public class RandomRetryPolicy : IRetryPolicy
{
private readonly Random _random = new Random();
public TimeSpan? NextRetryDelay(RetryContext retryContext)
{
// If we've been reconnecting for less than 60 seconds so far,
// wait between 0 and 10 seconds before the next reconnect attempt.
if (retryContext.ElapsedTime < TimeSpan.FromSeconds(60))
{
return TimeSpan.FromSeconds(_random.NextDouble() * 10);
}
else
{
// If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
return null;
}
}
}
HubConnection connection = new HubConnectionBuilder()
.WithUrl(new Uri("http://127.0.0.1:5000/chathub"))
.WithAutomaticReconnect(new RandomRetryPolicy())
.Build();
Кроме того, можно написать код для повторного подключения клиента вручную, как показано в следующем разделе.
Повторное подключение вручную
Warning
В версиях ниже 3.0 клиент .NET для SignalR не переподключается автоматически. Для повторного подключения клиента необходимо написать код вручную.
Closed Используйте событие для реагирования на потерянное соединение. Например, может потребоваться автоматизировать повторное подключение.
Для Closed события требуется делегат, который возвращает объект Task, который позволяет асинхронный код выполняться без использования async void. Чтобы сигнатура делегата в обработчике событий Closed, который выполняется синхронно, соответствовала требованиям, верните Task.CompletedTask:
connection.Closed += (error) => {
// Do your close logic.
return Task.CompletedTask;
};
Основная причина асинхронной поддержки заключается в том, что вы можете перезапустить подключение. Запуск соединения — это асинхронное действие.
В обработчике Closed , который перезапускает подключение, рекомендуется ожидать некоторой случайной задержки, чтобы предотвратить перегрузку сервера, как показано в следующем примере:
connection.Closed += async (error) =>
{
await Task.Delay(new Random().Next(0,5) * 1000);
await connection.StartAsync();
};
Методы концентратора вызовов из клиента
InvokeAsync вызывает методы в концентраторе. Передайте в InvokeAsync имя метода концентратора и все аргументы, определенные для метода концентратора.
SignalR является асинхронным, поэтому используйте async и await при выполнении вызовов.
await connection.InvokeAsync("SendMessage",
userTextBox.Text, messageTextBox.Text);
Метод InvokeAsync возвращает Task значение, которое завершается при возврате метода сервера. Возвращаемое значение, если таковое имеется, предоставляется в качестве результата Task. Все исключения, вызванные методом на сервере, вызывают сбой Task. Используйте синтаксис await, чтобы дождаться завершения метода сервера, и синтаксис try...catch для обработки ошибок.
Метод SendAsync возвращает объект Task, который завершается после отправки сообщения на сервер. Возвращаемое значение не предоставляется, так как это Task не ожидает завершения метода сервера. Все исключения, вызванные клиентом при отправке сообщения, вызывают ошибку Task. Используйте синтаксис await и try...catch для обработки ошибок отправки сообщений.
Note
Вызов методов концентратора из клиента поддерживается только при использовании службы Azure SignalR в режиме Default. Дополнительные сведения см. в разделе Часто задаваемые вопросы.
Вызов клиентских методов из концентратора
Определите методы, которые вызывает концентратор, используя connection.On после сборки, но перед началом подключения:
connection.On<string, string>("ReceiveMessage", (user, message) =>
{
this.Dispatcher.Invoke(() =>
{
var newMessage = $"{user}: {message}";
messagesList.Items.Add(newMessage);
});
});
Предыдущий код в connection.On выполняется, когда код на стороне сервера вызывает его с помощью метода SendAsync:
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
Хотя сторона подключения, связанная с концентратором, поддерживает строго типизированный обмен сообщениями, клиент должен зарегистрировать метод, используя универсальный метод HubConnection.On и указав имя метода. Пример см. в разделе Размещение ASP.NET Core SignalR в фоновых службах.
Обработка ошибок и ведение журнала
Обрабатывайте ошибки с помощью инструкции try...catch.
Exception Проверьте объект, чтобы определить правильное действие, выполняемое после возникновения ошибки:
try
{
await connection.InvokeAsync("SendMessage",
userTextBox.Text, messageTextBox.Text);
}
catch (Exception ex)
{
messagesList.Items.Add(ex.Message);
}
Связанный контент
ASP.NET Core