Guía de la API Hubs de ASP.NET SignalR: cliente .NET (C#)

Advertencia

Esta documentación no se aplica a la última versión de SignalR. Eche un vistazo a SignalR de ASP.NET Core.

En este documento ofrece una introducción al uso de la API Hubs para SignalR versión 2 en clientes .NET, como la Tienda Windows (WinRT), WPF, Silverlight y aplicaciones de consola.

La API Hubs de SignalR le permite realizar llamadas a procedimientos remotos (RPC) desde un servidor a los clientes conectados y desde los clientes al servidor. En el código del servidor, se definen los métodos a los que pueden llamar los clientes y se llama a los métodos que se ejecutan en el cliente. En el código cliente, se definen métodos a los que se puede llamar desde el servidor, y se llama a métodos que se ejecutan en el servidor. SignalR se encarga de todas las conexiones cliente-servidor por usted.

SignalR también ofrece una API de nivel inferior llamada Persistent Connections. Para una introducción a SignalR, Hubs y Persistent Connections, o para un tutorial que muestra cómo desarrollar una aplicación de SignalR completa, consulte SignalR: Introducción.

Versiones de software empleadas en este tema

Versiones anteriores de este tema

Para obtener información sobre versiones anteriores de SignalR, consulte Versiones anteriores de SignalR.

Preguntas y comentarios

Deje sus comentarios sobre este tutorial y sobre lo que podríamos mejorar en los comentarios en la parte inferior de la página. Si tiene alguna pregunta que no esté directamente relacionadas con el tutorial, puede publicarla en el foro de ASP.NET SignalR o en StackOverflow.com.

Información general

Este documento contiene las siguientes secciones:

Para ver un ejemplo de proyectos de cliente de .NET, consulte los siguientes recursos:

Para obtener documentación sobre cómo programar el servidor o los clientes de JavaScript, consulte los siguientes recursos:

Los vínculos a los temas de referencia de la API corresponden a la versión .NET 4.5 de la API. Si está usando .NET 4, consulte la versión .NET 4 de los temas de API.

Configuración del cliente

Instale el paquete NuGet Microsoft.AspNet.SignalR.Client (no el paquete Microsoft.AspNet.SignalR). Este paquete admite clientes WinRT, Silverlight, WPF, aplicación de consola y Windows Phone para .NET 4 y .NET 4.5.

Si la versión de SignalR que tiene en el cliente es diferente de la versión que tiene en el servidor, SignalR suele ser capaz de adaptarse a la diferencia. Por ejemplo, un servidor que ejecute SignalR versión 2 admitirá los clientes que tengan instalada la versión 1.1.x, así como los clientes que tengan instalada la versión 2. Si la diferencia entre la versión del servidor y la versión del cliente es demasiado grande, o si el cliente es más reciente que el servidor, SignalR produce una excepción InvalidOperationException cuando el cliente intenta establecer una conexión. El mensaje de error es "You are using a version of the client that isn't compatible with the server. Client version X.X, server version X.X".

Establecimiento de una conexión

Para poder establecer una conexión, debe crear un objeto HubConnection y luego un proxy. Para establecer la conexión, llame al método Start en el objeto HubConnection.

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

Nota:

Para los clientes de JavaScript, debe registrar al menos un controlador de eventos antes de llamar al método Start para establecer la conexión. Esto no es necesario para los clientes de .NET. En el caso de los clientes de JavaScript, el código de proxy generado crea automáticamente servidores proxy para todos los centros que existen en el servidor y el registro de un controlador es la forma en que se indica qué centros quiere usar el cliente. Pero para un cliente de .NET, crea servidores proxy del centro manualmente, por lo que SignalR supone que va a usar cualquier centro para el que cree un proxy.

El código de ejemplo usa la URL "/signalr" predeterminada para conectarse a su servicio SignalR. Para obtener información sobre cómo especificar una URL base diferente, consulte Guía de la API Hubs de ASP.NET SignalR - Servidor: URL /signalr.

El método Start se ejecuta de forma asincrónica. Para asegurarse de que las siguientes líneas de código no se ejecuten hasta después de establecer la conexión, utilice await en un método asincrónico ASP.NET 4.5 o .Wait() en un método sincrónico. No use .Wait() en un cliente de WinRT.

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

Conexiones entre dominios de clientes de Silverlight

Para obtener información sobre cómo habilitar conexiones entre dominios desde clientes de Silverlight, consulte Disponibilidad de un servicio más allá de límites de dominio.

Configuración de la conexión

Antes de establecer una conexión, puede especificar cualquiera de las siguientes opciones:

  • Límite de conexiones simultáneas.
  • Parámetros de cadena de consulta.
  • Método de transporte.
  • Encabezados HTTP.
  • Certificados de cliente.

Establecimiento del número máximo de conexiones simultáneas en clientes WPF

En los clientes de WPF, es posible que tenga que aumentar el número máximo de conexiones simultáneas a partir de su valor predeterminado de 2. El valor recomendado es 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 más información, consulte ServicePointManager.DefaultConnectionLimit.

Especificación de los parámetros de la cadena de consulta

Si quiere enviar datos al servidor cuando el cliente se conecte, puede agregar parámetros de cadena de consulta al objeto de conexión. El siguiente ejemplo muestra cómo establecer un parámetro de cadena de consulta en el código del cliente.

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

El siguiente ejemplo muestra cómo leer un parámetro de cadena de consulta en el código del servidor.

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

Especificación del método de transporte

Como parte del proceso de conexión, un cliente de SignalR normalmente negocia con el servidor para determinar el mejor transporte compatible tanto con el servidor como con el cliente. Si ya sabe qué transporte desea usar, puede omitir este proceso de negociación. Para especificar el método de transporte, pase un objeto de transporte al método Start. En el ejemplo siguiente se muestra cómo especificar el método de transporte en el código del 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());
}

El espacio de nombres Microsoft.AspNet.SignalR.Client.Transports incluye las siguientes clases que puede usar para especificar el transporte.

El transporte ForeverFrame no se incluye en esta lista porque solo lo usan los exploradores.

Para obtener información sobre cómo comprobar el método de transporte en el código del servidor, consulte Guía de la API Hubs de ASP.NET SignalR - Servidor: Obtención de información sobre el cliente a partir de la propiedad Context. Para más información sobre los transportes y las reservas, consulte Introduction a SignalR: Transportes y las reservas.

Especificación de encabezados HTTP

Para establecer encabezados HTTP, utilice la propiedad Headers en el objeto de conexión. En el siguiente ejemplo se muestra cómo agregar un encabezado 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();

Especificación de certificados de cliente

Para agregar certificados de cliente, use el método AddClientCertificate en el objeto de conexión.

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

Creación del proxy del centro

Para definir métodos en el cliente al que un centro pueda llamar desde el servidor e invocar métodos en un centro en el servidor, cree un proxy para el centro llamando a CreateHubProxy en el objeto de conexión. La cadena que pasa a CreateHubProxy es el nombre de la clase Hub o el nombre especificado por el atributo HubName si se ha utilizado uno en el servidor. La coincidencia de nombres no distingue mayúsculas y minúsculas.

Clase Hub en el servidor

public class StockTickerHub : Hub

Creación de un proxy de cliente para la clase 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();
}

Si decora la clase Hub con un atributo HubName, utilice ese nombre.

Clase Hub en el servidor

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

Creación de un proxy de cliente para la clase 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();
}

De hecho, si llama a HubConnection.CreateHubProxy varias veces con el mismo hubName, obtendrá el mismo objeto IHubProxy almacenado en caché.

Definición de métodos en el cliente que el servidor puede llamar

Para definir un método al que puede llamar el servidor, use el método On del proxy para registrar un controlador de eventos.

La coincidencia de nombres de métodos no distingue entre mayúsculas y minúsculas. Por ejemplo, Clients.All.UpdateStockPrice en el servidor ejecutará updateStockPrice, updatestockprice o UpdateStockPrice en el cliente.

Las distintas plataformas de cliente tienen requisitos diferentes sobre la forma de escribir código de método para actualizar la interfaz de usuario. Los ejemplos que se muestran son para los clientes de WinRT (Windows Store .NET). Los ejemplos de WPF, Silverlight y aplicación de consola se proporcionan en una sección independiente más adelante en este tema.

Métodos sin parámetros

Si el método que controla no tiene parámetros, use la sobrecarga no genérica del método On:

Código de servidor que llama al método de cliente sin parámetros

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

Código de cliente de WinRT para un método llamado desde el servidor sin parámetros (consulte ejemplos de WPF y Silverlight posteriormente en este tema)

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 con parámetros, que especifican tipos de parámetros

Si el método que controla tiene parámetros, especifique los tipos de los parámetros como tipos genéricos del método On. Hay sobrecargas genéricas del método On que le permiten especificar hasta 8 parámetros (4 en Windows Phone 7). En el ejemplo siguiente, se envía un parámetro al método UpdateStockPrice.

Código de servidor que llama al método de cliente con un parámetro

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

Clase Stock usada para el parámetro

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

Código de cliente de WinRT para un método llamado desde el servidor con un parámetro (consulte ejemplos de WPF y Silverlight posteriormente en este tema)

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 con parámetros, que especifican objetos dinámicos para los parámetros

Como alternativa a la especificación de parámetros como tipos genéricos del método On, puede especificar parámetros como objetos dinámicos:

Código de servidor que llama al método de cliente con un parámetro

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

Clase Stock usada para el parámetro

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

Código de cliente de WinRT para un método llamado desde el servidor con un parámetro mediante un objeto dinámico para el parámetro (consulte ejemplos de WPF y Silverlight posteriormente en este tema)

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

Supresión de un controlador

Para quitar un controlador, llame a su método Dispose.

Código de cliente para un método llamado desde el 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 de cliente para quitar el controlador

updateStockPriceHandler.Dispose();

Llamada a los métodos del servidor desde el cliente

Para llamar a un método en el servidor, use el método Invoke en el proxy del centro.

Si el método de servidor no tiene ningún valor devuelto, use la sobrecarga no genérica del método Invoke.

Código de servidor para un método que tiene ningún valor devuelto

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

Código de cliente que llama a un método que no tiene ningún valor devuelto

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

Si el método de servidor tiene un valor devuelto, especifique el tipo de valor devuelto como tipo genérico del método Invoke.

Código de servidor para un método que tiene un valor devuelto y toma un parámetro de tipo complejo

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

Clase Stock usada para el parámetro y el valor devuelto

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

Código de cliente que llama a un método que tiene un valor devuelto y toma un parámetro de tipo complejo, en un método asincrónico de 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 de cliente que llama a un método que tiene un valor devuelto y toma un parámetro de tipo complejo, en un método sincrónico

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

El método Invoke se ejecuta de forma asincrónica y devuelve un objeto Task. Si no especifica await o .Wait(), la siguiente línea de código se ejecutará antes de que el método que invoque haya terminado de ejecutarse.

Control de eventos de duración de la conexión

SignalR proporciona los siguientes eventos de duración de la conexión que puede controlar:

  • Received: se genera cuando se recibe algún dato en la conexión. Proporciona los datos recibidos.
  • ConnectionSlow: se genera cuando el cliente detecta una conexión lenta o que se cae con frecuencia.
  • Reconnecting: se genera cuando el transporte subyacente comienza a volver a conectarse.
  • Reconnected: se genera cuando el transporte subyacente se ha vuelto a conectar.
  • StateChanged: se genera cuando cambia el estado de conexión. Proporciona el estado anterior y el nuevo. Para más información sobre los valores de estado de la conexión, consulte ConnectionState Enumeration.
  • Closed: se genera cuando la conexión está desconectada.

Por ejemplo, si desea mostrar mensajes de advertencia para errores que no son irrecuperables, pero que causan problemas de conexión intermitentes, como lentitud o caída frecuente de la conexión, controle el evento ConnectionSlow.

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

Para más información, consulte Descripción y control de los eventos de duración de conexión en SignalR.

Control de errores

Si no habilita explícitamente mensajes de error detallados en el servidor, el objeto de excepción que devuelve SignalR tras un error contiene información mínima sobre el mismo. Por ejemplo, si se produce un error en una llamada a newContosoChatMessage, el mensaje de error en el objeto de error contiene "There was an error invoking Hub method 'contosoChatHub.newContosoChatMessage'.". No se recomienda enviar mensajes de error detallados a los clientes en producción por razones de seguridad, pero si quiere habilitar los mensajes de error detallados para solucionar problemas, use el siguiente código en el servidor.

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

Para controlar los errores que genera SignalR, puede agregar un controlador para el evento Error en el objeto de conexión.

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

Para controlar los errores desde las invocaciones de método, encapsule el código en un bloque 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);
}

Habilitación del registro del lado del cliente

Para habilitar el registro del lado cliente, establezca las propiedades TraceLevel y TraceWriter en el objeto de conexión.

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

Ejemplos de código de WPF, Silverlight y aplicación de consola para los métodos de cliente a los que el servidor puede llamar

Los ejemplos de código mostrados anteriormente para definir métodos de cliente a los que el servidor puede llamar se aplican a los clientes de WinRT. En los ejemplos siguientes se muestra el código equivalente para los clientes de WPF, Silverlight y aplicación de consola.

Métodos sin parámetros

Código de cliente de WPF para un método llamado desde el servidor sin parámetros

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

Código de cliente de Silverlight para un método llamado desde el servidor sin parámetros

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

Código de cliente de la aplicación de consola para un método llamado desde el servidor sin parámetros

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

Métodos con parámetros, que especifican tipos de parámetros

Código de cliente de WPF para un método llamado desde el servidor con un 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 de cliente de Silverlight para un método llamado desde el servidor con un 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 de cliente de la aplicación de consola para un método llamado desde el servidor con un parámetro

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

Métodos con parámetros, que especifican objetos dinámicos para los parámetros

Código de cliente de WPF para un método llamado desde el servidor con un parámetro, mediante un objeto dinámico para el 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 de cliente de Silverlight para un método llamado desde el servidor con un parámetro, mediante un objeto dinámico para el 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 de cliente de la aplicación de consola para un método llamado desde el servidor con un parámetro, mediante un objeto dinámico para el parámetro

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