.NET - Apresentando SignalR


Interatividade em tempo real, acesso de múltiplos usuários atuando colaborativamente e acesso assíncrono são algumas das dificuldades que temos que transpor para criarmos uma aplicação Web com uma experiência rica ao usuário final.

A herança dos protocolos que sustentam a web conspiram contra nós pois estão baseados em um modelo cliente-servidor síncrono. Funciona assim: um ou vários clientes realizam uma conexão com o servidor e transmitem uma ação a realizar, o servidor processa a informação e retorna uma resposta encerrando a conexão.

Para poder romper estas barreiras teríamos que ter uma conexão persistente, sempre aberta entre o cliente e o servidor, de forma a permitir o envio e o recebimento de mensagens e eventos de forma bidirecional em tempo real. Até algum tempo atrás, a única maneira de conseguirmos isso seria com a utilização de sockets, o que requer a existência de algum tipo de elemento ativo na página (Flash, SilverLight, Applets, etc.) capaz de estabelecer esse tipo de conexão.

Obs: O advento do AJAX teve como objetivo amenizar estes problemas tornando a comunicação na web mais dinâmica, mas mesmo assim, a comunicação HTTP era direcionada pelo cliente exigindo a interação do usuário ou a verificação periódica do servidor.

Felizmente uma luz no fim do túnel parece surgir: são os WebSockets.

A nova API WebSocket permite abrir conexões diretas a partir do navegador usando JavaScript. Em uma definição formal temos:

WebSocket é uma tecnologia que permite a comunicação bidirecional por canais full-dulplex sobre um único soquete Transmission Control Protocol (TCP). Ela é projetado para ser executada em navegadores e servidores web que suportem o HTML5, mas pode ser usado por qualquer cliente ou servidor de aplicativos. A API WebSocket está sendo padronizada pelo W3C e o protocolo WebSocket está sendo padronizado pelo IETF.

(fonte: http://pt.wikipedia.org/wiki/WebSockets acessado em janeiro de 2013)

Obs: Você pode ver uma demonstração desta tecnologia neste link: http://html5demos.com/web-socket (usando o navegador Chrome)

SignalR é uma biblioteca desenvolvida por alguns funcionários da Microsoft da equipe ASP .NET que tem o objetivo de criar aplicações web permitindo a interatividade em tempo real, combinando uma biblioteca ASP .NET no lado do servidor e uma biblioteca JavaScript do lado cliente para manter a comunicação cliente/servidor aberta.

Com SignalR podemos trabalhar praticamente como uma conexão sempre aberta onde no servidor poderemos detectar quando um novo cliente se conectou e se desconectou, enviar e receber mensagens dos clientes, etc.

Na verdade, as conexões persistentes realmente não existem sendo apenas uma abstração criada pela SignalR que faz o trabalho sujo por trás dos panos mantendo a conexão dos clientes com o servidor usando mecanismos de transportes (WebSockets) que são um conjunto de tecnologias usadas para manter a 'ilusão' da conexão contínua.

Dessa forma a biblioteca SignalR simplifica a criação e a gestão de conexões persistentes entre clientes e servidores web. Isso facilita o desenvolvimento de aplicações que podem mostrar atualizações de dados mantidos no servidor em tempo real. Aplicações de comunicação instantânea como os Chats são um exemplo mais óbvio de uso destes recursos.

O site do projeto pode ser acessado neste link: http://signalr.net/ e o código fonte está disponível aqui: https://github.com/SignalR/SignalR.

A tecnologia ainda esta em desenvolvimento e não funciona em todos os navegadores mas dá suporte ao SilverLight, WinRT, JavaScript, WindowsPhone7.

Até o momento a biblioteca permite duas formas de criarmos conexões:

  1. PersistentConnection  (namespace SignalR) - Classe base utilizada para expor o serviço de broadcast do SignalR no protocolo Http.
  2. Hub (namespace SignalR.Hubs)  - Classe base que permite transmitir diversos tipos de mensagens entre cliente/servidor sem a necessidade criação de uma rota;

Para usar quaisquer um dos tipos de conexões citadas acima basta criar uma classe que herde a sua respectiva classe base.

Usando o SignalR

O exemplo usado a seguir foi baseado integralmente no original :  Tutorial: Getting Started with SignalR (C#)

Este tutorial apresenta o desenvolvimento SignalR mostrando como construir uma aplicação Chat(bate-bapo) baseada no navegador. Durante a construção da aplicação iremos realizar as seguintes tarefas:

- Adicionar a biblioteca SignalR a uma aplicação web ASP.NET.
- Criar uma classe hub para enviar o conteúdo aos clientes.
- Usar a biblioteca jQuery SignalR em uma página web para enviar mensagens e atualizações de exibição a partir do hub.


A tela a seguir mostra o aplicativo de bate-papo em execução em um navegador. Cada novo usuário pode postar comentários e ver os comentários adicionados depois que o usuário se entra na sala de bate-papo.

Pré-Requisitos

Obs: Podemos também usar o Microsoft Visual Studio Express 2012 for web que grátis. Será essa ferramenta que eu irei usar neste artigo.

A tela inicial da instalação da ASP.NET e Web Tools 2012.2 e vista abaixo:

Ao clicar no botão Instalar será apresentada a tela exibindo os componentes a serem instalados:

Clique no botão Aceito e após alguns minutos ao final da instalação você deverá obter a mensagem abaixo:

Uma outra forma de usar a biblioteca SignalR é fazer o download da API e referenciá-la em seu projeto ASP .NET ou fazer a instalação via Nuget:

PM> Install-Package SignalR

Além disso para dar suporte ao IE 6 e IE 7 devemos instalar o JSON2 para permitir o envio de requisições XMLHttpRequest.

PM> Install-Package JSON2

Vamos precisar também da biblioteca jQuery a partir da versão 1.6.

Como já mencionei neste primeiro contato com o SignalR eu vou mostrar a sua utilização em uma aplicação Chat em um projeto ASP .NET Web Forms.

Abra o Microsoft Visual Studio Express 2012 for web e no menu File clique em New Project;

Selecione o template Visual C# -> Web -> ASP .NET Empty Web Application e informe o nome ChatSignalR e clique no botão OK;

No menu PROJECT clique em Add New Item e a seguir selecione o item : SignalR Hub Class , visto que iremos criar conexões usando a classe Hub:

Após clicar no botão Add e espiar a janela Solution Explorer você deverá ver uma pasta Scripts contendo as bibliotecas jquery.signalR conforme abaixo:

Observe que foi criada uma classe chamada ChatHub.cs. Altere o conteúdo deste arquivo substituindo o código original pelo código abaixo:

No menu PROJECT clique em Add New Item e a seguir selecione o item : Global Application Class , para incluir um arquivo global.asax no projeto:

Selecione e abra o arquivo e inclua as referências aos namespaces System.Web.Routing e Microsoft.AspNet.SignalR;

Inclua também o código abaixo no evento Application_Start();

No menu PROJECT clique em Add New Item e a seguir selecione o item : HTML Page, para incluir um página HTML no projeto:

Altere o seu nome para HtmlChat.html e clique no botão Add;

Substitua o código do arquivo HTML pelo código abaixo:

<!DOCTYPE html>
<html>
<head>
    <title>Chat SignalR Simples</title>
    <style type="text/css">
        .container {
            background-color: #99CCFF;
            border: thick solid #808080;
            padding: 20px;
            margin: 20px;
        }
    </style>
</head>
<body>
    <div class="container">
        <input type="text" id="mensagem" />
        <input type="button" id="enviamensagem" value="Send" />
        <input type="hidden" id="exibenome" />
        <ul id="discussion">
        </ul>
    </div>
    <!--Script references. -->
    <!--Reference the jQuery library. -->
    <script src="/Scripts/jquery-1.8.2.min.js" ></script>
    <!--Reference the SignalR library. -->
    <script src="/Scripts/jquery.signalR-1.0.0.js"></script>
    <!--Reference the autogenerated SignalR hub script. -->
    <script src="/signalr/hubs"></script>
    <!--Add script to update the page and send messages.--> 
    <script type="text/javascript">
        $(function () {
            // Declar um proxy para referenciar o  hub. 
            var chat = $.connection.chatHub;
            // Cria a função que o run pode chamar para mensagens de broadcast
            chat.client.broadcastMessage = function (nome, mensagem) {
                // Html encode exibe o nome e mensagem
                var encodednome = $('<div />').text(nome).html();
                var encodedMsg = $('<div />').text(mensagem).html();
                // Adiciona a mensagem na pagina
                $('#discussion').append('<li><strong>' + encodednome
                    + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');
            };
            // Pega o nome do usuário e armazena 
            $('#exibenome').val(prompt('Informe o seu nome :', ''));
            // Define o focus inicial para a caixa de mensagem
            $('#mensagem').focus();
            // Inicia a conexão
            $.connection.hub.start().done(function () {
                $('#enviamensagem').click(function () {
                    // Chama o método Send no  hub. 
                    chat.server.send($('#exibenome').val(), $('#mensagem').val());
                    // Limpa o textbox e reseta o focus para o proximo comentario
                    $('#mensagem').val('').focus();
                });
            });
        });
    </script>
</body>
</html>

Executando a aplicação teremos a solicitação para informação do usuário:

Será apresentada uma tela conforme abaixo:

Copie a URL da página, no meu exemplo : http://localhost:3997/HtmlChat.html, e abra  uma outra instância do navegador:

Será solicitada uma nova informação de nome de usuário:

Dessa forma teremos duas instância que poderão conversar como em um chat:

Abaixo a visualização das janelas após algum tempo:

Qualquer usuário que abrir uma instância e se identificar irá receber as mensagens dos demais usuários a partir do momento do login:

Esta singela aplicação de Chat usando SignalR demonstra duas tarefas básicas do desenvolvimento SignalR:

  1. A criação de um hub como o objeto principal de coordenação no servidor;
  2. A utilização da library JQuery para enviar e receber mensagens;

Usando Hubs

No código de exemplo a classe ChatHub que deriva da classe  Microsoft.AspNet.SignalR.Hub. Nesta classe o cliente chama o método Send para enviar uma nova mensagem e o hub envia uma mensagem para todos os clientes chamando o método  Clients.All.broadcastMessage()

O método Send demonstra os seguintes conceitos da classe hub:

SignalR com JQuery

A página HTML no código mostra como usar a library JQuery SignalR para se comunicar com o hub SignalR. As tarefas essenciais no código são a declaração de um proxy para referenciar o hub, a declaração da função que o servidor chama para enviar o conteúdo aos clientes e a inicialização da conexão para enviar mensagens para o hub.

O código a seguir declara um proxy hub var chat = $.connection.chatHub;

Abaixo temos o código usado para criar uma função callback no script. A classe hub no servidor chama esta função para enviar o conteúdo atualizado para cada cliente. As duas linhas que o HTML usa para dar o encode antes de exibir o conteúdo é opcional mas é uma forma simples de evitar a injeção de scripts:

// Cria a função que pode chamar para mensagens de broadcast

chat.client.broadcastMessage = function (nome, mensagem) {

                // Html encode exibe o nome e mensagem

           var encodednome = $('<div />').text(nome).html();

               var encodedMsg = $('<div />').text(mensagem).html();

                // Adiciona a mensagem na pagina

               $('#discussion').append('<li><strong>' + encodednome

               + '</strong>:&nbsp;&nbsp;' + encodedMsg + '</li>');

};

 

A setuir temos o código que mostra como abrir uma conexão com o hub. O código inicia a conexão e a passa para tratar o evento Click do botão Send na página HTML:

$.connection.hub.start().done(function () {

                 $('#enviamensagem').click(function () {

                 // Chama o método Send no hub.

                 chat.server.send($('#exibenome').val(), $('#mensagem').val());

                // Limpa o textbox e reseta o focus para o proximo comentario

                $('#mensagem').val('').focus();

             });

});

Vimos de forma bem simples os conceitos básicos do SignalR que esta em evolução. No exemplo criamos a conexão usando um Hub. Em outro exemplo irei mostrar como criar a conexão usando PersistentConnection.

Aguarde...

Pegue o projeto completo aqui: ChatSignalR.zip

1Pe 4:7 Mas já está próximo o fim de todas as coisas; portanto sede sóbrios e vigiai em oração;

1Pe 4:8 tendo antes de tudo ardente amor uns para com os outros, porque o amor cobre uma multidão de pecados;

1Pe 4:9 sendo hospitaleiros uns para com os outros, sem murmuração;

1Pe 4:10 servindo uns aos outros conforme o dom que cada um recebeu, como bons despenseiros da multiforme graça de Deus.

Referências:


José Carlos Macoratti