¿Por qué esperar? SignalR y Mobile Services para mensajes en tiempo real

En estas últimas semanas he estado trabajando en una aplicación que tiene un sistema de envío de mensajes, para estos mensajes se ha utilizado SignalR para mejorar la velocidad de entrega y vaya que es rápida la conexión y el envío de mensajes.

La aplicación a la que me refiero tenía un backend con Mobile Services el cual ya ofrece un Azure Service Bus que utilizamos como backplane para la distribución de los mensajes.

Este es un post con un breve ejemplo de cómo enviar mensajes entre las aplicaciones, como primer punto vamos a definir que es SignalR.

¿Qué es SignalR?

SignalR es una biblioteca open source desarrollada por miembros del equipo de ASP .Net y que nos sirve para conectar aplicaciones en tiempo real de una manera muy sencilla, SiganlR nos provee una capa de abstracción que nos permite utilizar diferentes transportes que inicia por Web Sockets y en caso de no ser soportados hace un proceso de fallback entre los diferentes tipos de conexión que soporta.

El proceso de fallback a grandes rasgos sería el siguiente, primero intentaría conectar por web sockets, en caso de no poder conectarse lo intentará con Server Sent Events, Forever Frames y Long Pollig sucesivamente hasta lograr una conexión.

Una de las características principales de SignalR es que nos permite simular una conexión persistente en el caso del HTTP y administra la conexión con web sockets que sí soportan una conexión persistente.

SignalR nos da también la habilidad de hacer "push" desde el servidor hacia el cliente, evitando que el cliente tenga que realizar conexiones al servidor para validar si existe nueva información, SignalR evita esto permitiendo al servidor realizar callback a los clientes.

Creando nuestro primer Signalr Hub

Lo primero que haremos es instalar los paquetes de Nuget que nos darán acceso a las características de SignalR en nuestro servidor.

Para esto iremos a la consola de Nuget y agregaremos la siguiente línea.

 Install-Package WindowsAzure.MobileServices.Backend.SignalR  

Una vez hemos agregado los paquetes a nuestro proyecto Web podemos crear nuestro hub, en este ejemplo crearemos un método que nos permita enviar un mensaje a todos los clientes conectados.

 [HubName("ChatHub")]
    public class ChatHub : Hub
    {
        public ApiServices Services { get; set; }

        public void Send(string message)
        {
            Clients.All.helloMessage(message);
        }
    }

Nota: Clients.All no es la única manera en la que podemos enviar mensajes, también tenemos Caller, Others, AllExcept, etc. te invito al leer el siguiente post para más información.

Después en el archivo WebApiConfig agregaremos el siguiente código para iniciar los servicios de SignalR.

 public static class WebApiConfig  
    {
        public static void Register()
        {
           //Initialize SignalR
           SignalRExtensionConfig.Initialize();            
        }
    }

Conectando nuestra aplicación

Ahora agregaremos los paquetes de Nuget para habilitar los servicios de SignalR en el cliente, como podrás notar en este ejemplo utilizaremos una aplicación universal.

Agrega la siguiente línea en la consola de Nuget.

 Install-Package Microsoft.AspNet.SignalR.Client  

Una vez se instalen los paquetes agregaremos el siguiente código para conectarnos con los servicios de SignalR.

 private IHubProxy proxy;  
private HubConnection hubConnection;

private async Task ConnectToSignalR()  
{
   //Se crea el hub utilizando la url de nuestro Mobile Service
   hubConnection = new HubConnection(App.MobileService.ApplicationUri.AbsoluteUri);  

   //Agregamos en los headers la llave de Mobile Service, de lo contrario no nos permitirá realizar la conexión 
   hubConnection.Headers["x-zumo-application"] = App.MobileService.ApplicationKey;

   //Creamos un proxy para conectarnos con el hub de chat que hemos creado previamente
   proxy = hubConnection.CreateHubProxy("ChatHub");
   // Iniciamos la conexión
   await hubConnection.Start();

   //Utilizaremos el método On para recibir la notificación cada vez que se utilice el mensaje "helloMessage".
   proxy.On<string>("helloMessage", async (msg) =>
   {
      await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
      {
         message += " " + msg;
         Message.Text = message;
      });
   });
}

Al navegar a la página conectaremos con el hub.

  protected override async void OnNavigatedTo(NavigationEventArgs e)
 {          
    await ConnectToSignalR();
 }

Después agregaremos el siguiente código en un botón para enviar información desde nuestra app y no solo recibir.

 private async void Button_OnClick(object sender, RoutedEventArgs e)  
{
   //Utilizaremos el método invoke cuando deseemos enviar un mensaje desde nuestra aplicación
   await proxy.Invoke<string>("Send", TextBox.Text);
   TextBox.Text = string.Empty;
}

Escalando con Azure Service Bus

En este caso al utilizar Mobile Service y tener un nivel de servicio básico o estándar (como es el caso que he platicado anteriormente) te tengo una buena noticia, ya tenemos habilitado Azure Service Bus para sincronizar nuestra entrega de mensajes en los clientes sin importar cuantas instancias tengamos trabajando. ¡Excelente! ¿No te parece?

La siguiente es una imagen que explica cómo funciona SignalR en conjunto con Azure Service Bus.

Nota: Azure Service Bus a pesar de ser un muy buen servicio no es el único con el que puedes trabajar ya que SignlR te permite trabajar también con Redis y con SQL Server.

Ahora ya podemos enviar mensajes en tiempo real a través de nuestras aplicaciones.

Te dejo él código del proyecto de ejemplo en github, como siempre espero te resulte útil y no olvides compartir.

¡Saludos!