Partilhar via


Cliente .NET ASP.NET Core SignalR

A biblioteca de cliente .NET do ASP.NET Core SignalR permite que você se comunique com SignalR hubs de aplicativos .NET.

Visualizar ou descarregar amostra de código (como descarregar)

O exemplo de código neste artigo é um aplicativo WPF que usa o cliente .NET ASP.NET Core SignalR .

Instalar o pacote cliente SignalR .NET

O pacote Microsoft.AspNetCore.SignalR.Client é necessário para que os clientes .NET se conectem a SignalR hubs.

Para instalar a biblioteca de cliente, execute o seguinte comando na janela Console do Gerenciador de Pacotes :

Install-Package Microsoft.AspNetCore.SignalR.Client

Conectar-se a um hub

Para estabelecer uma conexão, crie um HubConnectionBuilder e chame Build. A URL do hub, o protocolo, o tipo de transporte, o nível de log, os cabeçalhos e outras opções podem ser configurados durante a criação de uma conexão. Configure todas as opções necessárias inserindo qualquer um dos HubConnectionBuilder métodos no Build. Inicie a conexão com 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);                
            }
        }
    }
}

Lidar com a perda de conexão

Reconecte-se automaticamente

O HubConnection pode ser configurado para a reconexão automática usando o método WithAutomaticReconnect no HubConnectionBuilder. Ele não se reconectará automaticamente por padrão.

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

Sem quaisquer parâmetros, WithAutomaticReconnect() configura o cliente para aguardar 0, 2, 10 e 30 segundos, respectivamente, antes de tentar cada tentativa de reconexão, parando após quatro tentativas falhadas.

Antes de iniciar qualquer tentativa de reconexão, o HubConnection fará a transição para o HubConnectionState.Reconnecting estado e disparará o Reconnecting evento. Isso oferece uma oportunidade para avisar os usuários que a conexão foi perdida e desabilitar os elementos da interface do usuário. As aplicações não interativas podem começar a enfileirar ou soltar mensagens.

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

Se o cliente se reconectar com êxito nas suas primeiras quatro tentativas, a transição HubConnection voltará ao estado Connected e disparará o evento Reconnected. Isso oferece uma oportunidade de informar aos usuários que a conexão foi restabelecida e retirar da fila todas as mensagens enfileiradas.

Como a conexão é percebida como totalmente nova para o servidor, uma nova ConnectionId será fornecida aos manipuladores de eventos Reconnected.

Warning

O parâmetro do Reconnected manipulador de eventos será nulo se o connectionId foi configurado para HubConnection a negociação.

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() não configurará o para repetir as HubConnection falhas iniciais de inicialização, portanto, as falhas de inicialização precisam ser tratadas 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);
        }
    }
}

Se o cliente não se reconectar com êxito nas suas primeiras quatro tentativas, o HubConnection fará a transição para o estado Disconnected e disparará o evento Closed. Isso oferece uma oportunidade de tentar reiniciar a conexão manualmente ou informar aos usuários que a conexão foi perdida 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 um número personalizado de tentativas de reconexão antes de desconectar ou alterar o tempo de reconexão, WithAutomaticReconnect aceita uma matriz de números que representam o atraso em milissegundos para aguardar antes de iniciar cada tentativa de reconexão.

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.

O exemplo anterior configura o HubConnection para iniciar tentativas de reconexão imediatamente após a perda de conexão. Isso também é verdadeiro para a configuração padrão.

Se a primeira tentativa de reconexão falhar, a segunda tentativa de reconexão também será iniciada imediatamente, em vez de esperar 2 segundos, como faria na configuração padrão.

Se a segunda tentativa de reconexão falhar, a terceira tentativa de reconexão será iniciada em 10 segundos, o que é novamente como a configuração padrão.

Em seguida, o comportamento personalizado diverge novamente do comportamento padrão, parando após a falha da terceira tentativa de reconexão. Na configuração padrão, haveria mais uma tentativa de reconexão em mais 30 segundos.

Se você quiser ainda mais controle sobre o tempo e o número de tentativas de reconexão automática, WithAutomaticReconnect aceita um objeto que implementa a IRetryPolicy interface, que tem um único método chamado NextRetryDelay.

NextRetryDelay usa um único argumento com o tipo RetryContext. O RetryContext tem três propriedades: PreviousRetryCount, ElapsedTime e RetryReason, que são um long, a TimeSpan e um Exception respectivamente. Antes da primeira tentativa de nova conexão, PreviousRetryCount e ElapsedTime serão zero, e RetryReason será a Exceção que causou a perda da conexão. Depois de cada tentativa de repetição falhada, PreviousRetryCount será incrementado por um, ElapsedTime será atualizado para refletir a quantidade de tempo gasto reconectando até agora e a RetryReason Exceção que causou a falha da última tentativa de reconexão.

NextRetryDelay deve retornar um TimeSpan representando o tempo de espera antes da próxima tentativa de reconexão ou null se o deve parar de HubConnection se reconectar.

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, você pode escrever código que reconectará seu cliente manualmente, conforme demonstrado em Reconectar manualmente.

Reconectar manualmente

Warning

Antes da versão 3.0, o cliente .NET para SignalR não se reconecta automaticamente. Você deve escrever um código que reconectará seu cliente manualmente.

Use o Closed evento para responder a uma conexão perdida. Por exemplo, talvez você queira automatizar a reconexão.

O Closed evento requer um delegado que retorna um Task, que permite que o código assíncrono seja executado sem usar async voido . Para satisfazer a assinatura do delegado em um Closed manipulador de eventos executado de forma síncrona, retorne Task.CompletedTask:

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

A principal razão para o suporte assíncrono é para que você possa reiniciar a conexão. Iniciar uma conexão é uma ação assíncrona.

Em um Closed manipulador que reinicia a conexão, considere aguardar algum atraso aleatório para evitar sobrecarregar o servidor, conforme mostrado no exemplo a seguir:

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

Chamar métodos do hub a partir do cliente

InvokeAsync chama métodos no hub. Passe o nome do método hub e quaisquer argumentos definidos no método hub para InvokeAsync. SignalR é assíncrono, por isso use async e await ao fazer as chamadas.

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

O InvokeAsync método retorna um Task que é finalizado quando o método do servidor retorna. O valor de retorno, se houver, é fornecido como resultado do Task. Quaisquer exceções lançadas pelo método no servidor produzem uma falha Task. Use a sintaxe await para aguardar a conclusão do método do servidor e a sintaxe try...catch para manipular erros.

O SendAsync método retorna um Task que é concluído quando a mensagem foi enviada para o servidor. Nenhum valor de retorno é fornecido, pois isso Task não espera até que o método do servidor seja concluído. Quaisquer exceções lançadas no cliente ao enviar a mensagem resultam em um erro Task. Use a sintaxe de await e try...catch para lidar com erros de envio.

Note

A chamada de métodos de hub a partir de um cliente só é suportada ao utilizar o Serviço SignalR do Azure no modo Padrão. Para obter mais informações, consulte Perguntas frequentes.

Chamar métodos de cliente a partir do hub

Defina métodos que o hub chama usando connection.On após a criação, mas antes de iniciar a conexão.

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

O código anterior é executado connection.On quando o código do lado do servidor o chama usando o método SendAsync.

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

Note

Embora o lado do hub da conexão ofereça suporte a mensagens fortemente tipadas, o cliente deve se registrar usando o método genérico HubConnection.On, especificando o nome do método. Para obter um exemplo, consulte Host ASP.NET Core SignalR em serviços em segundo plano.

Tratamento e registo de erros

Manipule erros com uma instrução try-catch. Inspecione o Exception objeto para determinar a ação adequada a ser tomada após a ocorrência de um erro.

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

Recursos adicionais