April 2012

Volume 27 Number 04

Azure Insider - Implementing Pub/Sub Applications with SignalR

By Bruno Terkaly | April 2012

Imagine that you want to build a browser-based stock market application that displays the latest stock market information in as close to real time as possible. You want to support this application in all of the browsers that are currently popular. You would also like to support a number of clients in addition to the browser, such as .NET and others on the way. But that’s not all. The application must be scalable so that the back-end server isn’t overburdened as more and more browser-based users come online, and it must be able to support millions of users. In this scenario, you’re facing one of the more challenging use cases for browser-based applications. Scalable pub/sub systems are notoriously difficult to implement.

SignalR, a new technology from Microsoft that makes long polling practical and scalable, is the solution you’ve been waiting for to address the implementation headaches of pub/sub systems. The framework, available on GitHub, makes it easy to build asynchronous scalable Web applications with real-time, persistent and long-running connections. A number of technical innovations in recent years have made SignalR possible. David Fowler and Damian Edwards, the creators of SignalR, will tell you that SignalR would have been too challenging to implement a few years ago. Until the Task Parallel Library in .NET Framework 4 was introduced, writing multithreaded programs was just too difficult. Also, the development of jQuery made it possible to write JavaScript once and deploy it on Firefox, Internet Explorer, Safari, Opera and Chrome. The convergence of these various technologies has made creating and using SignalR technically feasible.

Before explaining how to create a SignalR application and host it on the cloud, let’s backtrack a bit and look at the problems inherent in traditional polling approaches.

AJAX Polling and Long Polling

The traditional approach to updating a browser with the latest information from the server is to poll the server at some predefined interval, say, every second or two. This approach generally works well for small numbers of users. As soon as you start scaling the number of users to a few dozen or more, however, you begin to compromise your server’s performance because of the extreme inefficiency of constant polling. Yet polling has been used historically because the Web is based on http, and http is stateless—connections are made and lost with every browser-based Web request. Simply put, http is designed around the concept of request/response, meaning that unless the browser “asks” for something, it won’t get it. So the question becomes, “How do I send changes from the server to the client browser without relying on a polling mechanism?”

Despite its limitations, AJAX polling is popular and works well if you know the interval at which data is changing. Unfortunately, you rarely know the frequency rate of updates. The trick is to tune the frequency of updates and provide a good balance between load on the server and timeliness of information reported to users. AJAX polling isn’t sufficient in some scenarios (e.g., stock market updates) because of the delays between events on the server and notification to the client.

In long polling, the client makes a request, stays connected and waits for the server to respond. The client closes the connection only when a valid response comes back from the server. Keeping the connection open isn’t a problem on the client, but open connections drain resources on the server. For each open connection the server must maintain one or more threads, and keeping connections open also reduces available threads. Fewer available threads on the server hampers scalability and slows the server’s response time for other client requests. To make long polling practical, you must carefully consider how to implement and maintain thread management on the server. Long polling eats server threads, so scaling can be a challenge.

Building a SignalR Application and Deploying It to the Cloud

SignalR offers new approaches to supporting a pub/sub model. Even if SignalR can support hundreds of thousands of connections on a single server, there may come a time when additional scale is needed. Azure is a cloud offering from Microsoft that makes it easy to host, deploy and scale a SignalR application.

I’ll now demonstrate how quickly you can build a SignalR application and deploy it to the cloud. I’m assuming you’ve installed the necessary tools and SDKs related to Azure, but if you need guidance, check out my blog post on getting set up.

Let’s first look at how you would implement the application, which allows one browser to broadcast a drag operation to other browsers. This means that if a user drags a shape in one browser, users on all other browsers will see the shape move on their own browser. If Browser #1 moves the gray shape, as shown in Figure 1, the shape will automatically move in Browser #2.

The pub/sub model in action
Figure 1 The pub/sub model in action

We don’t have the space in this column to show all the screen shots and all the detailed steps, but you can find those on my blog.

Here are some high-level steps to follow to create a SignalR application and host it in the cloud:

  1. Use Visual Studio 2010 to create a new Cloud project.
  2. Add an ASP.NET Web Role to the project. This will be the container for the Web application.
  3. Use NuGet to add the needed SignalR assemblies and references and some jQuery JavaScript modules.
  4. Create a server-side class that inherits from the SignalR intrinsic Hub. This is the server-side code that listens to Browser #1 and transmits the event to Browser #2.
  5. Create the client-side code, which is essentially some JavaScript and a Web page.
  6. Go to the Azure Management Portal and create a hosted service and a storage account.
  7. Package up the project (Steps 1–4) and deploy it to Azure.
  8. Tell Azure how many running instances you need (this is the elastic scale part). If necessary, you can adjust the number of running instances after deployment.
  9. Done!

Figure 2shows what the Visual Studio 2010 solution looks like when it’s complete.

Completed SignalR solution in Visual Studio
Figure 2 Completed SignalR solution in Visual Studio

The three key files added to the Visual Studio solution are described in Table 1.

Table 1 Modules That Enable SignalR

Module

Description

MoveShape.cs

This server-side SignalR file acts as a hub or central gateway to broadcast jQuery calls. This code listens to one browser and forwards user actions to other browsers.

MoveShape.js

This JavaScript in the browser gets called through the SignalR back-end server.

MoveShape.htm

This Web page is where all the action happens—that is, where a user drags a shape and other users can see the shape move on their browsers.

The server-side code that listens to browsers and then broadcasts to other browsers (step 4) is shown in Figure 3

Figure 3  MoveShape.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
// Add reference
using SignalR.Hubs;
namespace CloudSignalRSample_WebRole
{
    // Derive from Hub, which is a server-side class
    // and a client side proxy.
    [HubName("moveShape")]  // moveShape is the name used in the JavaScript
    public class MoveShapeHub : Hub
    {
        public void MoveShape(int x, int y)
        {
            // Broadcast to all connected browsers
            Clients.shapeMoved(Context.ConnectionId, x, y);
            // Simple diagnostics for debugging
            System.Diagnostics.Debug.WriteLine("x = " + x + ", y = " + y);
        }
    }
}

The code for the client-side Web page that broadcasts drag operations to other browsers (step 5) is shown in Figure 4. It’s basically a JavaScript file and a Web page. The Web page includes the MoveShape.js file. The shape defined in the code is dragged using some jQuery JavaScript.

Figure 4 MoveShape.htm

<!DOCTYPE html >
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <style type="text/css">
        #shape
        {  
            width: 200px;
            height: 200px;
            background: #ccc;
            border: 2px solid #333;
        }
        p { margin-left:10px; }
    </style>
</head>
<body>
    <div id="shape"></div>
    <script src="../Scripts/jquery-1.6.4.js" type="text/javascript"></script>
    <script src="../Scripts/jquery-ui-1.8.18.js" type="text/javascript"></script>
    <script src="../Scripts/jquery.signalR.js" type="text/javascript"></script>
    <script src="/signalr/hubs" type="text/javascript"></script>
    <script src="MoveShape.js" type="text/javascript"></script>
    <div>  <p>Hello</p></div><p></p>
</body>
</html>

The client-side JavaScript code that both broadcasts and receives drag events is shown in Figure 5. This code communicates with the “hub,” which is the service hosted by Azure. The code can receive a drag event from another browser, and it doesn’t respond to its own drag event based on this code:

if ($.connection.hub.hid !== cid) {

Figure 5 MoveShape.js

/// <reference path="Scripts/jquery-1.6.4.js" />
/// <reference path="Scripts/jquery.signalR.js" />
/// <reference path="Scripts/jquery-ui-1.8.18.js" />
$(function () {
    // Get a reference to the server-side moveShape() class.
    var hub = $.connection.moveShape,
    // Get a reference to the shape div in the html
    $shape = $("#shape");
    // Use extend to move the shape object (if we are not the sender)
    $.extend(hub, {
        // Use css to move the shape object
        shapeMoved: function (cid, x, y) {
            if ($.connection.hub.id !== cid) {
                $shape.css({ left: x, top: y });
                $("p:last").text("left: " + x + ", top: " + y);
            }
        }
    });
    // Wire up the draggable behavior (when hub is done starting)
    // "done" is a jQuery deferred method
    $.connection.hub.start().done(function () {
        $shape.draggable({
            // Implement draggable effect for jQuery
            drag: function () {
                // Tell the server that the shape was just dragged
                hub.moveShape(this.offsetLeft, this.offsetTop);
            }
        });
    })
});

SignalR is a major leap forward in lowering the technical barriers to creating asynchronous and scalable Web applications that work across all popular browsers. Combined with Azure, SignalR opens the door to many more types of applications that require frequent updates from the server. SignalR also works with non-browser clients, such as traditional desktop applications. In addition, SignalR is designed to leverage other high-level transports that aren’t based on long polling, such as WebSockets, server-sent events and the forever frame on Internet Explorer.

In the future, Microsoft plans to integrate SignalR as an official part of the Microsoft Web Platform, so now is the time to start experimenting with the release on GitHub. Rather than incorporating SignalR into .NET Framework, Microsoft will probably ship it as an officially supported out-of-band project like Model/View Controller, Web API, Web Pages and so on. SignalR has the potential to revolutionize the way browser-based applications are kept up to date with the latest server-based information. The high barriers to entry associated with creating supporting asynchronous and scalable cross-browser Web applications have now been dramatically reduced.


Bruno Terkaly  *works as a developer evangelist for Microsoft. His depth of knowledge comes from years of experience in the field, writing code using a multitude of platforms, languages, frameworks, SDKs, libraries and APIs. He spends time writing code, blogging and giving live presentations on building cloud-based applications, specifically using the Azure platform. *

Thanks to the following technical expert for reviewing this article: David Fowler.