in ASP.NET

Chat real-time com ASP.NET SignalR

Existem diversas dificuldades ao se desenvolver uma aplicação web real-time, entre as principais estão a latência de rede entre o seu usuário e seus servidores, o volume de conexões com o servidor, a maneira que o servidor trata as requisições que ficam esperando uma atualização, e a maneira que a interface client de sua aplicação atualiza as novas informações.

A fim de amenizar, e até resolver algumas destas dificuldades, várias técnicas (long pooling, pooling, etc) e tecnologias (WebSocket, Node.js e SignalR) foram desenvolvidas.

Há alguns meses assisti uma excelente apresentação do Damian Edwards, um dos criadores do ASP.NET SignalR, mostrando suas funcionalidades, performance e como a biblioteca funciona.

Conversando com alguns desenvolvedores, percebi que, essa biblioteca ainda é muito pouco conhecida e utilizada, por isso decidi fazer este post, para explicar o que é o ASP.NET SignalR, seus benefícios, seu uso, e finalmente, um exemplo de implementação utilizando o ASP.NET SignalR.

O que é o ASP.NET SignalR?

O ASP.NET SignalR é um biblioteca ASP.NET que facilita a implementação de aplicações web real-time, ele combina uma biblioteca ASP.NET Server Side, e uma biblioteca JavaScript client, a qual ajuda a manter a comunicação server-client.

O site do projeto é o: http://signalr.net/ e o código fonte está disponível em: https://github.com/SignalR/SignalR.

Além de poder fazer download e referenciar a biblioteca, o SignalR também pode ser instalado via nuget:

PM> Install-Package Microsoft.AspNet.SignalR -Pre

Uso do ASP.NET SignalR

O ASP.NET SignalR pode ser usado em diversos tipos de aplicações, como: jogos, aplicações colaborativas, aplicações sociais, aplicações de notícias, e qualquer outra que necessite de atualizações em tempo real.

Demo: Chat com ASP.NET SignalR

Como exemplo, vou criar um chat bem simples, para começar vou criar um projeto ASP.NET MVC4, e selecionar o template “Internet Aplication”.

image

image

Apos isso, vou instalar o ASP.NET SignalR via nuget:

image

Nosso próximo passo será mapear a rota default do script do SignalR, a rota default será “~/signalr/hubs”, para isso, vou referenciar o Microsoft.AspNet.SignalR no arquivo de registro das rotas (RouteConfig.cs) e vou utilizar o método responsável por registrar essa rota para o SignalR, o MapHubs().

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.AspNet.SignalR;

namespace ChatDemoSignalR
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            RouteTable.Routes.MapHubs();

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

Com essa rota definida, vou criar uma pasta chamada Hubs, e dentro dela, uma classe chamada ChatHub.cs

image

Nessa classe, vou adicionar referencia da namespace: Microsoft.AspNet.SignalR.Hubs, e também farei essa classe herdar da classe Hub do SignalR. Basicamente, um Hub é uma classe que conecta todos os clientes e faz a comunicação entre eles. Assim, o servidor utilizará essa classe para se comunicar com os clientes e transmitir mensagens para todos eles. A classe ChatHub.cs ficará da seguinte maneira:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR.Hubs;

namespace ChatDemoSignalR.Hubs
{
    public class ChatHub: Hub
    {
    }
}

Feito isso, vou adicionar um método publico nessa classe chamado EnviarMensagem, que recebe como parâmetro suas strings, o nome e a mensagem.:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR.Hubs;

namespace ChatDemoSignalR.Hubs
{
    public class ChatHub: Hub
    {
        public void EnviarMensagem(string nome, string mensagem)
        {

        }
    }
}

Esse método fará o broadcast dessa mensagem para todos os clientes que estão conectados na aplicação, para isso, dinamicamente eu vou chamar o método “publicarMensagem” , para todos os clientes, a propriedade dinâmica Clients representa todos os clientes que estão conectados na aplicação, e o método publicarMensagem é uma representação de uma função client (js) que é definida no client side.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR.Hubs;

namespace ChatDemoSignalR.Hubs
{
    public class ChatHub: Hub
    {
        public void EnviarMensagem(string nome, string mensagem)
        {
            Clients.All.publicarMensagem(nome, mensagem);
        }
    }
}

Após isso, podemos criar um arquivo chamado chat.js ou até mesmo definir os métodos js no próprio html. Como eu criei o Chat.js, vou referenciar o script do jquery e do plugin jquery do SignalR. A primeira coisa a se fazer é criar uma função jQuery e criar um objeto chamado hub, com o nome da minha classe em C#. por convenção iniciando em minúsculo:

/// <reference path="jquery-1.7.1.min.js" />
/// <reference path="jquery.signalR-1.0.0-rc1.js" />

$(function () {
    var chat = $.connection.chatHub;
});

O passo seguinte será definir a implementação daquela função que chamamos dinamicamente no C# ( publicarMensagem )

/// <reference path="jquery-1.7.1.min.js" />
/// <reference path="jquery.signalR-1.0.0-rc1.js" />

$(function () {
    var chat = $.connection.chatHub;

    chat.client.publicarMensagem = function (nome, mensagem) {
        var containerNome = $('<span/>').text(nome).html();
        var containerMensagem = $('<div/>').text(mensagem).html();

        $("#conversa").append(
            '<li><strong>'
                + containerNome +
                '</strong>: '
                + containerMensagem + '</li>');
    }; 

});

A ultima parte que precisaremos implementar nesse js será o método que inicializa a conexão com o hub, e, quando essa conexão estiver estabelecida, vamos definir o método que enviará a mensagem para o server, método o qual fará o broadcast para todos os clients.

/// <reference path="jquery-1.7.1.min.js" />
/// <reference path="jquery.signalR-1.0.0-rc1.js" />

$(function () {
    var chat = $.connection.chatHub;

    chat.client.publicarMensagem = function (nome, mensagem) {
        var containerNome = $('<span/>').text(nome).html();
        var containerMensagem = $('<div/>').text(mensagem).html();

        $("#conversa").append(
            '<li><strong>'
                + containerNome +
                '</strong>: '
                + containerMensagem + '</li>');
    };

    $.connection.hub.start().done(function () {
        $("#enviar").click(function () {
            var nome = $("#nome").val();
            var mensagem = $("#mensagem").val();

            chat.server.enviarMensagem(nome, mensagem);

            $("#mensagem").val('');
        });
    });

});

Agora, vamos partir para o html, nesse caso por ser um projeto ASP.NET MVC 4.0 vou editar a View chamada Index, da pasta Home, primeiro vou remover a laytou e adicionar as tags htmls. após isso, devemos adicionar referencias de alguns scripts, o primeiro será o jQuery (~/Scripts/jquery-1.7.1.min.js), o seguindo será o plugin jQuery para o SignalR (~/Scripts/jquery.signalR-1.0.0-rc1.min.js), o terceiro script referenciado é o do SignalR (~/signalr/hubs), ele é o mais importante, este script é acessível por aquela rota que foi definido no começo da demo, e ele consiste em um script gerado dinamicamente a partir das classes que herdam da classe Hub no C#, o ultimo script é onde programamos a conexão e as implementações client (~/Scripts/Chat.js).

@{
    ViewBag.Title = "Home Page";
    Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
</head>
<body>

    <script src="~/Scripts/jquery-1.7.1.min.js"></script>
    <script src="~/Scripts/jquery.signalR-1.0.0-rc1.min.js"></script>
    <script src="~/signalr/hubs"></script>
    <script src="~/Scripts/Chat.js"></script>

</body>
</html>

Após isso, a única coisa que falta para funcionar é criar a estrutura html para inserir o nome, a mensagem a ser enviada, e a estrutura com as mensagens recebidas, o que deixará a nossa View da seguinte maneira:

@{
    ViewBag.Title = "Home Page";
    Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
</head>
<body>

    <p>
        Nome
    <input type="text" id="nome" name="nome" />
    </p>

    <p>Mensagem:<input type="text" id="mensagem" name="mensagem" /></p>
    <input type="button" value="Enviar" id="enviar" name="enviar" />

    <br />
    <br />
    <ul id="conversa">
    </ul>
    <script src="~/Scripts/jquery-1.7.1.min.js"></script>
    <script src="~/Scripts/jquery.signalR-1.0.0-rc1.min.js"></script>
    <script src="~/signalr/hubs"></script>
    <script src="~/Scripts/Chat.js"></script>

</body>
</html>

Após esses passos já podemos testar nossa aplicação abrindo vários browsers, ou até publicado ela para várias pessoas testarem.

Abaixo segue um vídeo de como ficou o funcionamento:

O projeto está no meu github:

https://github.com/rodolfofadino/ChatDemoSignalR

e pode ser baixado em:

https://github.com/rodolfofadino/ChatDemoSignalR/archive/master.zip

Espero que este post seja útil, estou a disposição para dúvidas, criticas e sugestões

Abs

Rodolfo

  • Rafael Gazze

    Muito Bom parabens !!

  • Rodrigo

    Olá Rodolfo, você saberia me dizer se SignalR roda em ASP.NET 2.0?

    Parabéns pelo post

  • http://www.rodolfofadino.com.br/ Rodolfo Fadino

    Valeu Rodrigo 🙂
    o SignalR não roda em ASP.NET 2.0.

    Uma alternativa é criar um projeto em ASP.NET 4.0 para hopedar o hub e consumir ele (client side) na sua aplicação em ASP.NET 2.0.

    abs

  • http://www.facebook.com/paulo.furtado.14 Paulo Furtado

    Li em alguns fóruns que posso determinar para qual cliente quero mandar a mensagem
    algo como

    Clients[id_usuario].broadcastMessage(name, message);

    porem esta dando erro, dizendo que nao posso aplicar um index em Clients.

    Como faço se quiser que somente um usuario receba a mensagem?

    obrigado

  • http://www.rodolfofadino.com.br/ Rodolfo Fadino

    Você pode especificar o cliente que receberá a mensagem da seguinte maneira: Clients.Client(“ConnectionId”).publicarMensagem(nome, mensagem);

    doc: https://github.com/SignalR/SignalR/wiki/Hubs

    Vê se funciona para vc.

    abs

  • http://www.facebook.com/people/Rodrigo-Liz/100000668981472 Rodrigo Liz

    Muito bom adorei o artigo, sou novo na programação, que saber se podia me dar uma ajuda de como faço para uma o cliente colocar o nick em uma imput e depois ser redirecionada para a sala de chat, muito obrigado se pode me ajudar,

  • Vinicius

    Muito bom!!

  • Rodolfo6030 .

    Primeiramente meus parabéns Rodolfo pelo tutorial.

    Gostaria de saber se você tem algum exemplo do SignalR sendo consumido por um Windows Forms.

    Fico no aguardo.