Build real-time, multi-user interactive web apps with SignalR

A while back I was involved in developing an online-bidding app. This may not sound too exciting nor complicated, but because this kind of application was web-based, it introduced a whole new set of challenges. One of the core requirements of this app was to be critically up-to-date with real-time results. As a user bids on something, the action needs to be broadcast to the rest of the players bidding. The main challenge was achieving this on the web.

The way web applications work, is the client sends a request to the server for certain information then the server sends back the response which contains the information. In our case where the client needed to be aware of certain server-side changes, the most obvious way was to poll the server periodically.

"Polling is a common example of hammering a screw. Trying to make a chat program? Poll every 5 seconds. Got a really long running transaction? Throw up an animated GIF and poll until eternity, my friend!" - Scott Hanselman

Another way to achieve this is a concept called Long Polling. Basically, open a connection and keep it open forcing the client to wait, pretending it's taking a long time to return. If you have enough control on your server-side programming model, this can allow you to return data as you like over this "open connection." If the connection breaks, it's transparently re-opened and the break is hidden from both sides. In the future things like WebSockets will be another way to solve this problem when it's baked.

Then SignalR came along

Doing this kind of persistent connection in an app (like our bidding site) hasn't been easy in ASP.NET because there hasn't been a decent abstraction for this on the server or client library to talk to it.

SignalR is an asynchronous signaling library to build real-time interactive multi-user web applications.

Easy elegant implementation

I'm not going into too much detail on this, the only thing I want to show is how easy we implement something as simple as a basic chat app.

In your web-app project - hopefully its MVC :) - install the SignalR NuGet package. You can also do this using the Package Manager Console:

Setup

Install-Package SignalR  

Server

Create a class that derives from Hub, then add a function "Send" that expects a message as string. We will then use the Clients property and call a dynamic function "addMessage":

public class Chat : Hub  
{
    public void Send(string message) 
    {
        Clients.addMessage(message);
    }
}

Client

Add references to JQuery, SignalR & the virtual path "/signalr/hubs"

<script src="Scripts/jquery-1.6.2.min.js" type="text/javascript"></script>  
<script src="Scripts/jquery.signalR-0.5.0.min.js" type="text/javascript"></script>  
<script src="/signalr/hubs" type="text/javascript"></script>  

The HTML:

<input type="text" id="msg" />  
<input type="button" id="broadcast" value="broadcast" />  
<ul id="messages"></ul>  

Next, we instantiate our server class as a proxy on the client-side:

<script type="text/javascript">  
$(function () {
    var chat = $.connection.chat;
    //...
});
</script>  

Keep in mind that the connection.chat directly translates to our Chat class (which derives from Hub).

Next, we declare a function on the chat hub so the server can invoke it:

chat.addMessage = function(message) {  
    $('#messages').append('<li>' + message + '</li>');
};

When we click the 'broadcast' button, we want to call the server-side "Send" function:

$("#broadcast").click(function () {
    chat.send($('#msg').val());
});

And last (but not least) we start the connection:

$.connection.hub.start();

This is not a lot of code, but yet again you probably can make it shorter and sexier using KnockoutJs (I blogged about it recently). SignalR will work really well with KnockoutJs.

Demo

There is a small chat application running on Azure at http://jabbr.net that was built with this technology. Feel free to check it out and give it a try.

I hope someone finds this useful.

Thanks! Until next time...

@FanieReynders

comments powered by Disqus