клиент .NET core SignalR ASP.NET
Клиентская библиотека .NET для ASP.NET Core SignalR позволяет взаимодействовать с SignalR центрами из приложений .NET.
Просмотреть или скачать образец кода (описание загрузки)
Пример кода в этой статье — это приложение WPF, использующее клиент ASP.NET Core SignalR .NET.
Установка клиентского SignalR пакета .NET
Microsoft.AspNetCore .SignalR. Пакет клиента необходим для подключения клиентов .NET к SignalR концентраторам.
Чтобы установить клиентную библиотеку, выполните следующую команду в окне консоли диспетчер пакетов:
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
событие. Это дает возможность сообщить пользователям о том, что подключение было восстановлено и удалено из очереди.
Так как подключение выглядит совершенно новым на сервере, новое ConnectionId
будет предоставлено обработчикам Reconnected
событий.
Предупреждение
Параметр Reconnected
обработчика connectionId
событий будет иметь значение 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
ElapsedTime
и RetryReason
, которые являются long
,a TimeSpan
и Exception
соответственно. Перед первой попыткой PreviousRetryCount
повторного подключения оба и ElapsedTime
будет нулевым, и RetryReason
будет исключение, которое привело к потере подключения. После каждой неудачной попытки PreviousRetryCount
повтора будет увеличиваться по одному, ElapsedTime
будет обновлено, чтобы отразить время повторного подключения до сих пор, и RetryReason
будет исключение, которое вызвало последнюю попытку повторного подключения.
NextRetryDelay
должен возвращать значение TimeSpan, представляющее время ожидания перед следующей попыткой повторного подключения или null
HubConnection
если необходимо прекратить повторное подключение.
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();
Кроме того, можно написать код, который будет повторно подключать клиент вручную, как показано в ручном повторном подключении.
Повторное подключение вручную
Предупреждение
До версии 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
синтаксис для обработки ошибок отправки.
Примечание.
Вызов методов концентратора из клиента поддерживается только при использовании службы Azure SignalR в режиме по умолчанию . Дополнительные сведения см. в статье "Часто задаваемые вопросы" (репозиторий Azure-GitHubsignalr).
Вызов клиентских методов из концентратора
Определите методы вызовов концентратора, используя после 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);
}
Примечание.
Хотя центральная сторона подключения поддерживает строго типизированные сообщения, клиент должен зарегистрировать с помощью универсального метода 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