Compartilhar via


Guia de API dos Hubs do ASP.NET SignalR – Cliente .NET (C#)

Aviso

Esta documentação não é para a versão mais recente do SignalR. Dê uma olhada em ASP.NET Core SignalR.

Este documento fornece uma introdução ao uso da API de Hubs para SignalR versão 2 em clientes .NET, como aplicativos da Windows Store (WinRT), WPF, Silverlight e console.

A API dos Hubs signalr permite que você faça RPCs (chamadas de procedimento remoto) de um servidor para clientes conectados e de clientes para o servidor. No código do servidor, você define métodos que podem ser chamados por clientes e chama métodos executados no cliente. No código do cliente, você define métodos que podem ser chamados do servidor e chama métodos executados no servidor. O SignalR cuida de todo o encanamento cliente-servidor para você.

O SignalR também oferece uma API de nível inferior chamada Conexões Persistentes. Para obter uma introdução ao SignalR, hubs e conexões persistentes ou para um tutorial que mostra como criar um aplicativo SignalR completo, consulte SignalR - Introdução.

Versões de software usadas neste tópico

Versões anteriores deste tópico

Para obter informações sobre versões anteriores do SignalR, consulte Versões mais antigas do SignalR.

Perguntas e comentários

Deixe comentários sobre como você gostou deste tutorial e o que poderíamos melhorar nos comentários na parte inferior da página. Se você tiver perguntas que não estão diretamente relacionadas ao tutorial, poderá postá-las no fórum do ASP.NET SignalR ou StackOverflow.com.

Visão geral

Este documento contém as seguintes seções:

Para obter um exemplo de projetos de cliente .NET, consulte os seguintes recursos:

Para obter a documentação sobre como programar o servidor ou clientes JavaScript, consulte os seguintes recursos:

Os links para tópicos de Referência de API são para a versão do .NET 4.5 da API. Se você estiver usando o .NET 4, consulte a versão do .NET 4 dos tópicos da API.

Configuração do cliente

Instale o pacote NuGet Microsoft.AspNet.SignalR.Client (não o pacote Microsoft.AspNet.SignalR ). Esse pacote dá suporte a clientes WinRT, Silverlight, WPF, console e Windows Phone para .NET 4 e .NET 4.5.

Se a versão do SignalR que você tem no cliente for diferente da versão que você tem no servidor, o SignalR geralmente poderá se adaptar à diferença. Por exemplo, um servidor que executa o SignalR versão 2 dará suporte a clientes que têm o 1.1.x instalado, bem como clientes que têm a versão 2 instalada. Se a diferença entre a versão no servidor e a versão no cliente for muito grande ou se o cliente for mais recente que o servidor, o SignalR gerará uma exceção InvalidOperationException quando o cliente tentar estabelecer uma conexão. A mensagem de erro é "You are using a version of the client that isn't compatible with the server. Client version X.X, server version X.X".

Como estabelecer uma conexão

Antes de estabelecer uma conexão, você precisa criar um HubConnection objeto e criar um proxy. Para estabelecer a conexão, chame o Start método no HubConnection objeto .

using (var hubConnection = new HubConnection("http://www.contoso.com/")) 
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start();
}

Observação

Para clientes JavaScript, você precisa registrar pelo menos um manipulador de eventos antes de chamar o Start método para estabelecer a conexão. Isso não é necessário para clientes .NET. Para clientes JavaScript, o código proxy gerado cria automaticamente proxies para todos os Hubs que existem no servidor e registrar um manipulador é como você indica quais Hubs seu cliente pretende usar. No entanto, para um cliente .NET, você cria proxies do Hub manualmente, portanto, o SignalR pressupõe que você usará qualquer Hub para o qual você criará um proxy.

O código de exemplo usa a URL padrão "/signalr" para se conectar ao serviço do SignalR. Para obter informações sobre como especificar uma URL base diferente, consulte ASP.NET Guia de API dos Hubs do SignalR – Servidor – A URL /signalr.

O Start método é executado de forma assíncrona. Para garantir que as linhas de código subsequentes não sejam executadas até que a conexão seja estabelecida, use await em um método assíncrono ASP.NET 4.5 ou .Wait() em um método síncrono. Não use .Wait() em um cliente WinRT.

await connection.Start();
connection.Start().Wait();

Conexões entre domínios de clientes silverlight

Para obter informações sobre como habilitar conexões entre domínios de clientes silverlight, consulte Tornando um serviço disponível entre limites de domínio.

Como configurar a conexão

Antes de estabelecer uma conexão, você pode especificar qualquer uma das seguintes opções:

  • Limite de conexões simultâneas.
  • Parâmetros de cadeia de caracteres de consulta.
  • O método de transporte.
  • Cabeçalhos HTTP.
  • Certificados de cliente.

Como definir o número máximo de conexões simultâneas em clientes do WPF

Em clientes WPF, talvez seja necessário aumentar o número máximo de conexões simultâneas de seu valor padrão de 2. O valor recomendado é 10.

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    ServicePointManager.DefaultConnectionLimit = 10;
    await hubConnection.Start();
}

Para obter mais informações, consulte ServicePointManager.DefaultConnectionLimit.

Como especificar parâmetros de cadeia de caracteres de consulta

Se você quiser enviar dados para o servidor quando o cliente se conectar, poderá adicionar parâmetros de cadeia de caracteres de consulta ao objeto de conexão. O exemplo a seguir mostra como definir um parâmetro de cadeia de caracteres de consulta no código do cliente.

var querystringData = new Dictionary<string, string>();
querystringData.Add("contosochatversion", "1.0");
var connection = new HubConnection("http://contoso.com/", querystringData);

O exemplo a seguir mostra como ler um parâmetro de cadeia de caracteres de consulta no código do servidor.

public class StockTickerHub : Hub
{
    public override Task OnConnected()
    {
        var version = Context.QueryString["contosochatversion"];
        if (version != "1.0")
        {
            Clients.Caller.notifyWrongVersion();
        }
        return base.OnConnected();
    }
}

Como especificar o método de transporte

Como parte do processo de conexão, um cliente SignalR normalmente negocia com o servidor para determinar o melhor transporte com suporte pelo servidor e pelo cliente. Se você já souber qual transporte deseja usar, poderá ignorar esse processo de negociação. Para especificar o método de transporte, passe um objeto de transporte para o método Start. O exemplo a seguir mostra como especificar o método de transporte no código do cliente.

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start(new LongPollingTransport());
}

O namespace Microsoft.AspNet.SignalR.Client.Transports inclui as seguintes classes que você pode usar para especificar o transporte.

O transporte ForeverFrame não está incluído nesta lista porque é usado apenas por navegadores.

Para obter informações sobre como marcar o método de transporte no código do servidor, consulte ASP.NET Guia de API dos Hubs do SignalR – Servidor – Como obter informações sobre o cliente da propriedade Context. Para obter mais informações sobre transportes e fallbacks, consulte Introdução ao SignalR – Transportes e Fallbacks.

Como especificar cabeçalhos HTTP

Para definir cabeçalhos HTTP, use a Headers propriedade no objeto de conexão. O exemplo a seguir mostra como adicionar um cabeçalho HTTP.

hubConnection = new hubConnection("http://www.contoso.com/");
connection.Headers.Add("headername", "headervalue");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await connection.Start();

Como especificar certificados de cliente

Para adicionar certificados de cliente, use o AddClientCertificate método no objeto de conexão.

hubConnection = new hubConnection("http://www.contoso.com/");
hubConnection.AddClientCertificate(X509Certificate.CreateFromCertFile("MyCert.cer"));
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await connection.Start();

Como criar o proxy do Hub

Para definir métodos no cliente que um Hub pode chamar do servidor e invocar métodos em um Hub no servidor, crie um proxy para o Hub chamando CreateHubProxy no objeto de conexão. A cadeia de caracteres para a CreateHubProxy qual você passa é o nome da classe Hub ou o nome especificado pelo HubName atributo se um foi usado no servidor. A correspondência de nome não diferencia maiúsculas de minúsculas.

Classe hub no servidor

public class StockTickerHub : Hub

Criar proxy de cliente para a classe Hub

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start();
}

Se você decorar sua classe hub com um HubName atributo , use esse nome.

Classe hub no servidor

[HubName("stockTicker")]
public class StockTickerHub : Hub

Criar proxy de cliente para a classe Hub

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("stockTicker");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
        Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start();
}

Se você chamar HubConnection.CreateHubProxy várias vezes com o mesmo hubName, obterá o mesmo objeto armazenado em IHubProxy cache.

Como definir métodos no cliente que o servidor pode chamar

Para definir um método que o servidor pode chamar, use o método do On proxy para registrar um manipulador de eventos.

A correspondência de nome de método não diferencia maiúsculas de minúsculas. Por exemplo, Clients.All.UpdateStockPrice no servidor executará updateStockPrice, updatestockpriceou UpdateStockPrice no cliente.

Diferentes plataformas de cliente têm requisitos diferentes de como você escreve o código de método para atualizar a interface do usuário. Os exemplos mostrados são para clientes WinRT (Windows Store .NET). Exemplos de aplicativo de console, Silverlight e WPF são fornecidos em uma seção separada mais adiante neste tópico.

Métodos sem parâmetros

Se o método que você está tratando não tiver parâmetros, use a sobrecarga não genérica do On método :

Método de cliente de chamada de código de servidor sem parâmetros

public class StockTickerHub : Hub
{
    public void NotifyAllClients()
    {
         Clients.All.Notify();
    }
}

Código do cliente WinRT para o método chamado do servidor sem parâmetros (consulte exemplos do WPF e do Silverlight mais adiante neste tópico)

using (var hubConnection = new HubConnection("http://www.contoso.com/")) 
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHub.On("notify", () =>
        // Context is a reference to SynchronizationContext.Current
        Context.Post(delegate
        {
            textBox.Text += "Notified!\n";
        }, null)
    );
    await hubConnection.Start();
}

Métodos com parâmetros, especificando os tipos de parâmetro

Se o método que você está tratando tiver parâmetros, especifique os tipos dos parâmetros como os tipos genéricos do On método . Há sobrecargas genéricas do On método para permitir que você especifique até 8 parâmetros (4 em Windows Phone 7). No exemplo a seguir, um parâmetro é enviado para o UpdateStockPrice método .

Método de cliente de chamada de código de servidor com um parâmetro

public void BroadcastStockPrice(Stock stock)
{
    context.Clients.Others.UpdateStockPrice(stock);
}

A classe Stock usada para o parâmetro

public class Stock
{
    public string Symbol { get; set; }
    public decimal Price { get; set; }
}

Código do cliente WinRT para um método chamado do servidor com um parâmetro (consulte exemplos do WPF e do Silverlight mais adiante neste tópico)

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Métodos com parâmetros, especificando objetos dinâmicos para os parâmetros

Como alternativa à especificação de parâmetros como tipos genéricos do On método , você pode especificar parâmetros como objetos dinâmicos:

Método de cliente de chamada de código de servidor com um parâmetro

public void BroadcastStockPrice(Stock stock)
{
    context.Clients.Others.UpdateStockPrice(stock);
}

A classe Stock usada para o parâmetro

public class Stock
{
    public string Symbol { get; set; }
    public decimal Price { get; set; }
}

Código do cliente WinRT para um método chamado do servidor com um parâmetro , usando um objeto dinâmico para o parâmetro (consulte exemplos do WPF e do Silverlight mais adiante neste tópico)

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Como remover um manipulador

Para remover um manipulador, chame seu Dispose método .

Código do cliente para um método chamado do servidor

var updateStockPriceHandler = stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Código do cliente para remover o manipulador

updateStockPriceHandler.Dispose();

Como chamar métodos de servidor do cliente

Para chamar um método no servidor, use o Invoke método no proxy do Hub.

Se o método de servidor não tiver nenhum valor retornado, use a sobrecarga não genérica do Invoke método .

Código do servidor para um método que não tem nenhum valor retornado

public class StockTickerHub : Hub
{
    public void JoinGroup(string groupName)
    {
        Groups.Add(Context.ConnectionId, groupName); 
    }
}

Código do cliente chamando um método que não tem valor retornado

stockTickerHubProxy.Invoke("JoinGroup", "SignalRChatRoom");

Se o método de servidor tiver um valor retornado, especifique o tipo de retorno como o tipo genérico do Invoke método .

Código do servidor para um método que tem um valor retornado e usa um parâmetro de tipo complexo

public IEnumerable<Stock> AddStock(Stock stock)
{
    _stockTicker.AddStock(stock);
    return _stockTicker.GetAllStocks();
}

A classe Stock usada para o parâmetro e o valor retornado

public class Stock
{
    public string Symbol { get; set; }
    public decimal Price { get; set; }
}

Código do cliente que chama um método que tem um valor retornado e usa um parâmetro de tipo complexo, em um método assíncrono ASP.NET 4,5

var stocks = await stockTickerHub.Invoke<IEnumerable<Stock>>("AddStock", new Stock() { Symbol = "MSFT" });
foreach (Stock stock in stocks)
{
    textBox.Text += string.Format("Symbol: {0} price: {1}\n", stock.Symbol, stock.Price);
}

Código do cliente chamando um método que tem um valor retornado e usa um parâmetro de tipo complexo, em um método síncrono

var stocks = stockTickerHub.Invoke<IEnumerable<Stock>>("AddStock", new Stock() { Symbol = "MSFT" }).Result;
foreach (Stock stock in stocks)
{
    textBox.Text += string.Format("Symbol: {0} price: {1}\n", stock.Symbol, stock.Price);
}

O Invoke método é executado de forma assíncrona e retorna um Task objeto . Se você não especificar await ou .Wait(), a próxima linha de código será executada antes que o método invocado termine de ser executado.

Como lidar com eventos de tempo de vida da conexão

O SignalR fornece os seguintes eventos de tempo de vida de conexão que você pode manipular:

  • Received: gerado quando todos os dados são recebidos na conexão. Fornece os dados recebidos.
  • ConnectionSlow: gerado quando o cliente detecta uma conexão lenta ou com frequência.
  • Reconnecting: gerado quando o transporte subjacente começa a se reconectar.
  • Reconnected: gerado quando o transporte subjacente é reconectado.
  • StateChanged: gerado quando o estado da conexão é alterado. Fornece o estado antigo e o novo estado. Para obter informações sobre valores de estado de conexão, consulte Enumeração ConnectionState.
  • Closed: gerado quando a conexão é desconectada.

Por exemplo, se você quiser exibir mensagens de aviso para erros que não são fatais, mas causam problemas intermitentes de conexão, como lentidão ou remoção frequente da conexão, manipule o ConnectionSlow evento.

hubConnection.ConnectionSlow += () => Console.WriteLine("Connection problems.");

Para obter mais informações, consulte Noções básicas e tratamento de eventos de tempo de vida da conexão no SignalR.

Como lidar com erros

Se você não habilitar explicitamente mensagens de erro detalhadas no servidor, o objeto de exceção retornado pelo SignalR após um erro conterá informações mínimas sobre o erro. Por exemplo, se uma chamada para newContosoChatMessage falhar, a mensagem de erro no objeto de erro contém "There was an error invoking Hub method 'contosoChatHub.newContosoChatMessage'." Enviar mensagens de erro detalhadas para clientes em produção não é recomendado por motivos de segurança, mas se você quiser habilitar mensagens de erro detalhadas para fins de solução de problemas, use o código a seguir no servidor.

var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
App.MapSignalR(hubConfiguration);

Para lidar com erros gerados pelo SignalR, você pode adicionar um manipulador para o Error evento no objeto de conexão.

hubConnection.Error += ex => Console.WriteLine("SignalR error: {0}", ex.Message);

Para lidar com erros de invocações de método, encapsule o código em um bloco try-catch.

try
{
    IEnumerable<Stock> stocks = await stockTickerHub.Invoke<IEnumerable<Stock>>("GetAllStocks");
    foreach (Stock stock in stocks)
    {
        Console.WriteLine("Symbol: {0} price: {1}", stock.Symbol, stock.Price);
    }
}
catch (Exception ex)
{
    Console.WriteLine("Error invoking GetAllStocks: {0}", ex.Message);
}

Como habilitar o log do lado do cliente

Para habilitar o log do lado do cliente, defina as TraceLevel propriedades e TraceWriter no objeto de conexão.

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    hubConnection.TraceLevel = TraceLevels.All;
    hubConnection.TraceWriter = Console.Out;
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start();
}

Exemplos de código de aplicativo WPF, Silverlight e console para métodos de cliente que o servidor pode chamar

Os exemplos de código mostrados anteriormente para definir métodos de cliente que o servidor pode chamar se aplicam a clientes WinRT. Os exemplos a seguir mostram o código equivalente para clientes de aplicativo WPF, Silverlight e console.

Métodos sem parâmetros

Código do cliente WPF para o método chamado do servidor sem parâmetros

stockTickerHub.On<Stock>("notify", () =>
    Dispatcher.InvokeAsync(() =>
        {
            SignalRTextBlock.Text += string.Format("Notified!");
        })
);

Código do cliente Silverlight para o método chamado do servidor sem parâmetros

stockTickerHub.On<Stock>("notify", () =>
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += "Notified!";
    }, null)
);

Código do cliente do aplicativo de console para o método chamado do servidor sem parâmetros

stockTickerHubProxyProxy.On("Notify", () => Console.WriteLine("Notified!"));

Métodos com parâmetros, especificando os tipos de parâmetro

Código do cliente WPF para um método chamado do servidor com um parâmetro

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Dispatcher.InvokeAsync(() =>
        {
            textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
        })
);

Código do cliente Silverlight para um método chamado do servidor com um parâmetro

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Código do cliente do aplicativo de console para um método chamado do servidor com um parâmetro

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Console.WriteLine("Symbol {0} Price {1}", stock.Symbol, stock.Price));

Métodos com parâmetros, especificando objetos dinâmicos para os parâmetros

Código do cliente WPF para um método chamado do servidor com um parâmetro , usando um objeto dinâmico para o parâmetro

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    Dispatcher.InvokeAsync(() =>
        {
            textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
        })
);

Código do cliente Silverlight para um método chamado do servidor com um parâmetro , usando um objeto dinâmico para o parâmetro

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Código do cliente do aplicativo de console para um método chamado do servidor com um parâmetro , usando um objeto dinâmico para o parâmetro

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    Console.WriteLine("Symbol {0} Price {1}", stock.Symbol, stock.Price));