Real-time Web Applications with SignalR

Real-time Web Applications with SignalR

Introduction

Web applications are supposed to be more and more interactive today. Displaying the most up-to-date information is very important for modern applications. Latest news updates, scores of a cricket match, or the KPI (Key Performance Indicators) of an enterprise application are good examples for that. There are three techniques of doing this.

  • Poll the server at constant intervals
  • Long polling
  • HTML 5 Web Sockets

Polling the server at constant intervals is the most common approach that is used in most of the applications, since it is straight forward to implement. However this approach can only deliver results in near real time. The results will be more accurate if the polling interval is low. However this will increase the bandwidth utilization and the load on the server.

Both long poling and Web Sockets allows real time communication with server. Web sockets specification is not yet a finalized standard and not all browsers and web servers support it. Long poling is kind of a hack to the HTTP protocol. SignalR library developed by Microsoft as an Open Source library that supports both these approaches to enable real time communication with the server.

This makes the web applications development with real-time data to be very easy with ASP.NET.

With modern rich web client applications becoming more and more popular, the importance of JSON API is getting more and more increased. SignalR will become one of the three JSON API styles to be used in future ASP.NET. The other two will be ASP.NET Web API and direct JSON responses return from normal MVC controls. Each of these API will be used for following functions,

  • Direct unstructured JSON API calls – Normal MVC controllers with JSON response (jQuery as client)
  • Structured RESTfull API – ASP.NET Web API (use upshot.js as the client)
  • API that supports realtime by-directional communication – SingalR (SignalR.js as client)

Add SignalR to your application

Adding SignalR to your application is very straight forward with NuGet.

  • Create an ASP.NET WebForm or MVC application (I use a WebForm sample in this example due to its simplicity).
  • Open your “Package Manager Console” using “Tools->Library Package Manager” menu option in VS 2010 SP1 and type,
    • PS> install-package signalr

Create your first SignalR Hub

SignalR supports two levels or API. A high level Hub API and low level Persisted Connection API. I am only covering high level Hub API in this blog since it is sufficient for most of our normal work.
Therefore first step to do is to add Hub to your web application. To do so, you just have to add a normal class that derived from the base class “SignalR.Hubs.Hub”. My hub class looks like the one below,

namespace MyNameSpace
{
    [SignalR.Hubs.HubName("testHub")]
    public class TestHub : SignalR.Hubs.Hub
    {

    }
}

Add following script references to your Site.Master page

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

Then create an ASPX page named “test1.aspx” with the above master page and add the following JavaScript and HTML code

    <div id="responsesDiv">
    </div>
   <script type="text/javascript">
        $(document).ready(function () {
            var hub = $.connection.testHub;

            hub.showMessage = function (message) {
                $("#responsesDiv").append(message + "<br/>");
            };

            $.connection.hub.start();
        });
    </script>

This JavaScript code automatically starts the connection with the above hub (“TestHub”) when test1.aspx page is loaded. In addition to that, this code registers a client side function “showMessage” with the hub. Now when serer wants to show a message, it can call this client side “showMessage” method to push that message to the client.

Usage Patterns

Broadcasting

If you want to broadcast the same results to all clients (like the latest news items or cricket match score) you can use one of the following patterns.
Broadcast results
Create a web page named “test2.aspx” and add a button to it. Write the following code in its button click event,

        protected void Button1_Click(object sender, EventArgs e)
        {
            var clients = GetClients();
            clients.showMessage("Hello World");
        }

        private static dynamic GetClients()
        {
            return AspNetHost.DependencyResolver.Resolve<IConnectionManager>().GetClients<TestHub>();
        }

Ensure that the following namespaces are added to the page,

using SignalR;
using SignalR.Hosting.AspNet;
using SignalR.Infrastructure;

Get clients method in this sample code shows how to retrieve all the clients registered with TestHub from outside of the hub. Button1_Click method uses this method to retrieve the Clients dynamic object and calls its showMessage method to call the corresponding JavaScript showMessage method in all registered client browsers.

Now, open test1.aspx and test2.aspx pages into two tabs of the browser and click Button1 of test2.aspx. Our “Hello World” message will appear in test1.aspx page immediately. You can try this with multiple tabs of test1.aspx opened.

Broadcast Requests from the same Hub

Sometimes you might want to use SignalR to trigger the broadcast. This can be achieved as follows.

Add following method to TestHub class,

public void Broadcast(string message)
{
    this.Clients.showMessage(message);
}

Clients property of the Hub class represents all the client registered with this hub. Therefore the above methods class showMessage method with the message value in all registered client side hubs.

Now, add an HTML button control (“<input type=’button’ />”) into your “test1.aspx” page with id “broadcastButton” and add the following JavaScript code in $(document).ready method,

$("#broadcastButton").click(function () {
    hub.broadcast("Test Message to All");
});

Now open multiple tabs of “test1.aspx” page and see the response to your broadcast button clicks.

Request – Response style communication using SignalR

Even though the primary purpose of SignalR is not to create Request-Response style communication, it is possible to do with SignalR. This can be achieved as shown below,

Add following method to TestHub class,

public string SayHello()
{
    return "Hello " + Context.User.Identity.Name;
}

This code uses the Context property of the Hub class to get the current user details (Ensure that Windows Authentication is enabled before doing this).

Now, add another HTML button control into your “test1.aspx” page with id “requestResponseButton” and add the following JavaScript code in $(document).ready method,

$("#requestResponseButton").click(function () {
    hub.sayHello()
        .done(function (response) {
            alert(response);
        });
});

Now open “test1.aspx” click this button and see the response.

Update Long Running Process status with SignalR

This is a common requirement in most web applications. SignalR makes this implementation very easy. In order to see how this works, add the following code to your TestHub class,


public void LongRunningMethod()
{
    Thread.Sleep(1000);
    this.Caller.showMessage("25% Completed");
    Thread.Sleep(1000);
    this.Caller.showMessage("50% Completed");
    Thread.Sleep(1000);
    this.Caller.showMessage("75% Completed");
    Thread.Sleep(1000);
    this.Caller.showMessage("Done");
}

This method simulates a log running process that updates its progress as it proceeds. It updates its status by calling the client side “showMessage” method. The Caller property of Hub class represents the current caller of the method.

Now, add another HTML button control into your “test1.aspx” page with id “longRunningMethodButton” and add the following JavaScript code in $(document).ready method,

$("#longRunningMethodButton").click(function () {
    hub.longRunningMethod();
});

Then open test1.aspx page and see the results.

Publisher – Subscriber Pattern with SignalR

Most of the use cases of SignalR will be based on this patter. Therefore SignalR has a built-in feature called “Groups” to support this use case. We can achieve this as follows,

Add following two methods to TestHub class,

public void Subscribe(string category)
{
    this.AddToGroup(category);
}

public void Publish(string category, string message)
{
    this.Clients[category].showMessage(message);
}

Above code consider each subscription category as the client grouping criteria and add the client connection to that group. Then whenever a message is received in Publish method, it calls the showMessage client side method of all connections added to the corresponding group.

Then create a new page named “test3.aspx” with the same master page and add the following HTML and JavaScript code into it.

    <div style="padding:10px">
        <input type="button" id="subscribeToCategoryAButton" value="Subscribe To Category A" />
        <input type="button" id="subscribeToCategoryBButton" value="Subscribe To Category B" />
    </div>
    <div style="padding:10px">
        <input type="button" id="publishToCategoryAButton" value="Publish To Category A" />
        <input type="button" id="publishToCategoryBButton" value="Publish To Category B" />
    </div>

    <div id="responsesDiv">
    </div>

    <script type="text/javascript">
        $(document).ready(function () {
            var hub = $.connection.testHub;

            hub.showMessage = function (message) {
                $("#responsesDiv").append(message + "<br/>");
            };

            $.connection.hub.start();

            $("#subscribeToCategoryAButton").click(function () {
                hub.subscribe("A");
            });

            $("#subscribeToCategoryBButton").click(function () {
                hub.subscribe("B");
            });

            $("#publishToCategoryAButton").click(function () {
                hub.publish("A", "Message to A");
            });

            $("#publishToCategoryBButton").click(function () {
                hub.publish("B", "Message to B");
            });
        });
    </script>

Now, open multiple tabs of this page and click on either “Subscribe to Category A” or “Subscribe to Category B” button in each page. Then click on either “Publish to Category A” or “Publish to Category B” buttons and see the response in each page.

Sample Code

The source code of the above sample application can be downloaded from here