Apresentando o SignalR

SignalR é um projeto open source hospedado no GitHub que possibilita a comunicação em tempo real entre os usuários de uma aplicação cliente-servidor. Esta biblioteca permite que o servidor proativamente envie dados ou chame métodos nos clientes.

A API do SignalR permite que código .NET no servidor invoque métodos Javascript nos navegadores através de RPC.

Apenas a característica do servidor executar métodos no cliente abre um leque de possibilidades interessantes. Alguns exemplos de uso são: aplicações web com alta interação entre os usuários; criação de documentos de forma colaborativa e principalmente jogos.

Veja alguns casos de sucesso:

Jogo desenvolvido construída com HTML5 e Javascript e que utiliza SignalR

Demonstração disponível em http://shootr.signalr.net e inclui acesso código fonte.

Sala de bate papo construída com HTML5 e Javascript e que utiliza SignalR

Disponível em: http://jabbr.net

Protocolos e técnicas de Transporte

O framework SignalR tentará usar a técnica de transporte mais adequada de acordo com as configurações do cliente e do servidor. No caso do cliente e do servidor permitirem o uso de um protocolo padronizado no HTML5, o melhor protocolo será usado. Caso, não seja possível o SignalR utilizará o modelo de programação Comet para estabelecer a comunicação em tempo real. Na prática o desenvolvedor pode usar diretamente qualquer uma das técnicas abaixo, entretanto o framework SignalR e elimina o trabalho de escolher a melhor opção. Podemos dividir em duas categorias HTML5 e Comet.

HTML5

Os protocolos padronizados pelo HTML5 são o WebSocket e o Server Sent Events,  sendo o primeiro mais completo e mais exigente e o último mais simples e compatível.

O WebSocket é o protocolo que melhor utiliza os recursos de memória e que permite transporte de mensagens do cliente para o servidor e também do servidor para o cliente. Os cenários de uso mais apropriados para este protocolo são em jogos ou em aplicações com troca de mensagens nas duas direções.

O protocolo Server Sent Events é um protocolo mais simples padronizado no HTML5 que permite apenas mover conteúdo do servidor para o cliente. Cenários indicados de uso desta tecnologia são atualização automática de feed de notícias ou atualização dinâmica de cotações de moeda.

Comet

Comet é um modelo de programação que mantem aberta uma conexão HTTP por onde o servidor pode enviar dados sem necessidade de uma requisição explícita do navegador. Comet não é um protocolo, não necessita de componentes de terceiros e sua implementação pode ser feita usando os recursos básicos do navegador.

A técnica de transporte Forever Frame usa de um IFrame escondido por onde servidor pode enviar conteúdo para o cliente. O servidor então envia códigos Javacript que são executados assim que recebidos. O maior benefício desta técnica é ser compatível com os navegadores comuns.

Na técnica de transporte Long Polling são criadas requisições ajax ao servidor. Esta requisição é mantida aberta pelo maior tempo possível aguardando por novos dados. Assim que a resposta chega no cliente uma nova requisição Ajax é feita.

Processo de Escolha do Protocolo

Hello World – Seu Primeiro Programa com SignalR

O código a seguir você encontra na pasta Códigos\Capítulo01\SignalR01.

O passo a passo a seguir irá ensinar como criar uma Sala de Bate Papo utilizando o SignalR.

Crie um novo ASP.NET Project e na tela seguinte escolha Empty e clique em OK. Acesse o Package Manager Console (Tools > Library Package Manager > Package Manager Console) e digite o seguinte comando:

01

PM> Install-Package Microsoft.AspNet.SignalR

Este comando baixa as bibliotecas e dependências necessárias para o desenvolvimento com o framework SignalR.

Crie um arquivo App.js na raiz da aplicação com o código abaixo:

Arquivo: App.js

$(function () {
	$("#btnEnviar").click(function () {
    		var mensagem = $("#txtMensagem").val();
    		$.connection.batePapoHub.server.distribuirMensagem(mensagem);
	});
	$.connection.batePapoHub.client.adicionarMensagem =
    		function (connectionId, horario, mensagem) {
        			$("#ulHistorico").append(
            				"<li>" +
                					"<i>" + horario + "</i>" +
                					"<b>" + connectionId + "</b>" + mensagem +
            				"");
    	};
	$.connection.hub.start();
});

Este código associa uma função ao evento click do botão com o ID igual a “btnEnviar”. Este método recebe o valor do campo txtMensagem e guarda em uma variável mensagem.

Este método acessa a classe batePapoHub que permite acessar os métodos no servidor. O método sendo chamado no servidor é o distribuirMensagem(mensagem).

Este código Javascript também define um método para receber dados do servidor. Observe a função adicionarMensagem(connectionId, horario, mensagem). Neste capítulo você verá como chamar esta função através do BatePapoHub no servidor. Este método recebe os dados e adiciona em uma UL os argumentos já formatados.

Por último, o método start() da API do SignalR é responsável por estabelecer a conexão. Agora, você já pode desenvolver o Hub no servidor. Adicione ao projeto um arquivo BatePapoHub.cs do tipo SignalR Hub Class (v2). E modifique conforme abaixo:

Arquivo: BatePapoHub.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
namespace SignalR_01
{
	public class BatePapoHub : Hub
	{
    		public void DistribuirMensagem(string mensagem)
    		{
        			Clients.All.AdicionarMensagem(
				     this.Context.ConnectionId,
                  DateTime.Now.ToString("HH:mm:ss"), 
				     mensagem);
    		}
	}
}

A classe BatePapoHub define o método DistribuirMensagem(string mensagem) que é chamado pelos clientes, como no arquivo App.js. Este método recebe os argumentos e utiliza a API do SignalR para distribuir a mensagem executando o método AdicionarMensagem(..).

A propriedade ConnectionId identifica individualmente cada conexão. Neste exemplo ela é usada para mostrar quem enviou a mensagem.

A classe Hub permite filtrar os clientes. No exemplo acima o BatePapoHub chamará o método AdicionarMensagem(..) em todos os clientes.

É necessário inicializar o SignalR no servidor para o seu correto funcionamento. Crie o arquivo Startup.cs do tipo OWIN Startup Class no projeto e modifique conforme abaixo:

Arquivo: Startup.cs

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(SignalR_01.Startup))]
namespace SignalR_01
{
	public class Startup
	{
    		public void Configuration(IAppBuilder app)
    		{
        			app.MapSignalR();
    		}
	}
}

O código acima define que o SignalR escutará a URL padrão /SignalR. A classe de inicialização é definida usando o framework Owin através do atributo OwinStartup().

Você deve criar na raiz da aplicação o arquivo Index.html. Veja a estrutra deste arquivo abaixo:

Arquivo: Index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title></title>
	<link href="Style.css" rel="stylesheet" />
</head>
<body>
	<div class="content">
    		<ul id="ulHistorico">
    		</ul>
    		<input id="txtMensagem" type="text" />
    		<input id="btnEnviar" type="button" value="Enviar" />
	</div>
	<script src="/Scripts/jquery-1.6.4.min.js"></script>
	<script src="/Scripts/jquery.signalR-2.0.0.js"></script>
	<script src="/signalr/hubs"></script>
	<script src="App.js"></script>
</body>
</html>

No código acima temos a estrutura da tela de bate papo e temos as referências aos arquivos criados nos passos anteriores. Caso algum arquivo não esteja sendo carregado corretamente, verifique se a versão do jQuery instalada é a mesma sendo referenciada. A mesma atenção com a versão do SignalR.

O arquivo /SignalR/Hubs não existe durante desenvolvimento. Neste arquivo são criadas automaticamente as classes Javascript para troca de mensagens com os Hubs no servidor.

O último passo é criar o arquivo Style.css na raiz da aplicação. Este arquivo apenas irá diagramar a tela. Veja:

Arquivo: Style.css

.content {
	padding: 1em;
	background-color: #EEEEDD;
	border: 1px solid #CCC;
	max-width: 655px;
}
	.content ul {
    		height: 200px;
    		overflow-y: scroll;
	}
	.content input {
    		font-family: Arial;
	}
	.content p {
    		margin-top: 0.9em;
    		margin-bottom: 0.9em;
	}
	.content b {
    		margin-right: 0.5em;
	}
	.content i {
    		margin-right: 0.5em;
	}

Após as etapas anteriores, basta pressionar F5 para depurar a aplicação. Abrir uma outra janela de bate papo e trocar mensagens entre os dois navegadores. Veja o funcionamento:

No exemplo deste capítulo. Os clientes chamam o método DistribuirMensagem() no servidor que chama o método AdicionarMensagem em todos os clientes. Para melhor entendimento veja o diagrama de comunicação abaixo: