SignalRASP.NET Core Cliente de .NET

La ASP.NET Core SignalR cliente de .NET le permite comunicarse con SignalR centros desde aplicaciones .NET.

Vea o descargue el código de ejemplo (cómo descargarlo)

El ejemplo de código de este artículo es una aplicación WPF que usa el ASP.NET Core SignalR .NET.

Instalación del SignalR paquete de cliente .NET

Microsoft.AspNetCore. SignalR . El paquete de cliente es necesario para que los clientes de .NET se conecten a SignalR los centros.

Para instalar la biblioteca cliente, ejecute el siguiente comando en la Administrador de paquetes consola:

Install-Package Microsoft.AspNetCore.SignalR.Client

Conectar a un centro

Para establecer una conexión, cree y llame a HubConnectionBuilder Build . La dirección URL del centro, el protocolo, el tipo de transporte, el nivel de registro, los encabezados y otras opciones se pueden configurar al crear una conexión. Configure las opciones necesarias insertando cualquiera de los HubConnectionBuilder métodos en Build . Inicie la conexión con 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);                
            }
        }
    }
}

Control de la conexión perdida

Volver a conectar automáticamente

se HubConnection puede configurar para volver a conectarse automáticamente mediante el método en WithAutomaticReconnect HubConnectionBuilder . No se volverá a conectar automáticamente de forma predeterminada.

HubConnection connection= new HubConnectionBuilder()
    .WithUrl(new Uri("http://127.0.0.1:5000/chathub"))
    .WithAutomaticReconnect()
    .Build();

Sin ningún parámetro, configura el cliente para esperar 0, 2, 10 y 30 segundos respectivamente antes de intentar cada intento de reconexión, deteniéndose después de cuatro WithAutomaticReconnect() intentos fallidos.

Antes de iniciar los intentos de reconexión, HubConnection pasará al estado y se HubConnectionState.Reconnecting desenlazará el Reconnecting evento. Esto proporciona una oportunidad para advertir a los usuarios de que se ha perdido la conexión y deshabilitar los elementos de la interfaz de usuario. Las aplicaciones no interactivas pueden iniciar la puesta en cola o la colocación de mensajes.

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;
};

Si el cliente se vuelve a conectar correctamente dentro de sus cuatro primeros intentos, volverá a pasar HubConnection al estado y se Connected desenlazará el Reconnected evento. Esto proporciona una oportunidad para informar a los usuarios de que la conexión se ha restablecido y quitar de la cola los mensajes en cola.

Puesto que la conexión parece completamente nueva para el servidor, se proporciona un nuevo a ConnectionId los controladores Reconnected de eventos.

Advertencia

El Reconnected parámetro del controlador de eventos será NULL si se connectionId HubConnection configuró para omitir la negociación.

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() no configurará para reintentar los errores de inicio iniciales, por lo que los errores de inicio deben HubConnection controlarse manualmente:

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);
        }
    }
}

Si el cliente no se vuelve a conectar correctamente dentro de sus cuatro primeros intentos, el pasará al estado y HubConnection Disconnected se desenlazará el Closed evento. Esto proporciona una oportunidad para intentar reiniciar la conexión manualmente o informar a los usuarios de que la conexión se ha perdido permanentemente.

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;
};

Para configurar un número personalizado de intentos de reconexión antes de desconectarse o cambiar el tiempo de reconexión, acepta una matriz de números que representa el retraso en milisegundos que se debe esperar antes de iniciar cada intento de WithAutomaticReconnect reconexión.

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.

En el ejemplo anterior se configura para HubConnection que empiece a intentar volver a conectarse inmediatamente después de que se pierda la conexión. Esto también se aplica a la configuración predeterminada.

Si se produce un error en el primer intento de reconexión, el segundo intento de reconexión también se iniciará inmediatamente en lugar de esperar 2 segundos como lo haría en la configuración predeterminada.

Si se produce un error en el segundo intento de reconexión, el tercer intento de reconexión se iniciará en 10 segundos, que es de nuevo como la configuración predeterminada.

A continuación, el comportamiento personalizado difiere de nuevo del comportamiento predeterminado al detenerse después del tercer error de intento de reconexión. En la configuración predeterminada, habría un intento de reconexión más en otros 30 segundos.

Si desea tener aún más control sobre el tiempo y el número de intentos de reconexión automática, acepta un objeto que implementa la interfaz , que tiene WithAutomaticReconnect un único método denominado IRetryPolicy NextRetryDelay .

NextRetryDelay toma un único argumento con el tipo RetryContext . tiene RetryContext tres propiedades: PreviousRetryCount , y , que son , y , y , ElapsedTime RetryReason long TimeSpan Exception respectivamente. Antes del primer intento de reconexión, y serán cero, y será la excepción que hizo que PreviousRetryCount se perdiera la ElapsedTime RetryReason conexión. Después de cada intento de reintento con error, se incrementará en uno, se actualizará para reflejar la cantidad de tiempo invertido en volver a conectarse hasta ahora y será la excepción que hizo que se produjese un error en el último intento de PreviousRetryCount ElapsedTime RetryReason reconexión.

NextRetryDelay debe devolver un TimeSpan que representa el tiempo de espera antes del siguiente intento de reconexión o si debe dejar de volver a null HubConnection conectarse.

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();

Como alternativa, puede escribir código que vuelva a conectar el cliente manualmente, como se muestra en Volver a conectar manualmente.

Volver a conectar manualmente

Advertencia

Antes de la versión 3.0, el cliente de .NET para SignalR no se vuelve a conectar automáticamente. Debe escribir código que vuelva a conectar el cliente manualmente.

Use el Closed evento para responder a una conexión perdida. Por ejemplo, es posible que quiera automatizar la reconexión.

El evento requiere un delegado que devuelve , que permite que el código Closed asincrónico se ejecute sin usar Task async void . Para satisfacer la firma de delegado en un controlador Closed de eventos que se ejecuta sincrónicamente, devuelva Task.CompletedTask :

connection.Closed += (error) => {
    // Do your close logic.
    return Task.CompletedTask;
};

El motivo principal de la compatibilidad asincrónica es que puede reiniciar la conexión. Iniciar una conexión es una acción asincrónica.

En un controlador que reinicie la conexión, considere la posibilidad de esperar algún retraso aleatorio para evitar la sobrecarga del servidor, como se muestra Closed en el ejemplo siguiente:

connection.Closed += async (error) =>
{
    await Task.Delay(new Random().Next(0,5) * 1000);
    await connection.StartAsync();
};

Métodos del centro de llamadas desde el cliente

InvokeAsync llama a métodos en el centro. Pase el nombre del método central y los argumentos definidos en el método de concentrador a InvokeAsync . SignalR es asincrónico, por lo que debe async usar y al realizar las await llamadas.

await connection.InvokeAsync("SendMessage", 
    userTextBox.Text, messageTextBox.Text);

El InvokeAsync método devuelve un que se completa cuando el método de servidor devuelve Task . El valor devuelto, si existe, se proporciona como resultado de Task . Las excepciones producidas por el método en el servidor generan un error Task . Use await la sintaxis para esperar a que se complete el método de servidor y try...catch la sintaxis para controlar los errores.

El SendAsync método devuelve un que se completa cuando el mensaje se ha enviado al Task servidor. No se proporciona ningún valor devuelto, ya que esto no espera hasta que se complete Task el método de servidor. Las excepciones que se producen en el cliente al enviar el mensaje generan un error Task . Use await la try...catch sintaxis y para controlar los errores de envío.

Nota

La llamada a métodos de concentrador desde un cliente solo se admite cuando se usa el servicio de Azure SignalR en modo predeterminado. Para más información, consulte Preguntas más frecuentes (azure-signalr GitHub repositorio).

Llamada a métodos de cliente desde el centro

Defina los métodos que el centro llama connection.On mediante después de la creación, pero antes de iniciar la conexión.

connection.On<string, string>("ReceiveMessage", (user, message) =>
{
    this.Dispatcher.Invoke(() =>
    {
       var newMessage = $"{user}: {message}";
       messagesList.Items.Add(newMessage);
    });
});

El código anterior de connection.On se ejecuta cuando el código del lado servidor lo llama mediante el método SendAsync .

public async Task SendMessage(string user, string message)
{
    await Clients.All.SendAsync("ReceiveMessage", user,message);
}

Nota

Aunque el lado central de la conexión admite mensajería fuertemente typed, el cliente debe registrarse mediante el método genérico HubConnection.On con el nombre del método. Para obtener un ejemplo, consulte Host ASP.NET Core SignalR en servicios en segundo plano.

Registro y control de errores

Controle los errores con una instrucción try-catch. Inspeccione el Exception objeto para determinar la acción adecuada que se debe realizar después de que se produzca un error.

try
{
    await connection.InvokeAsync("SendMessage", 
        userTextBox.Text, messageTextBox.Text);
}
catch (Exception ex)
{                
    messagesList.Items.Add(ex.Message);                
}

Recursos adicionales