Getting started with SignalR in ASP.NET MVC

The publish / subscription pattern is a messaging pattern where messages are broadcast by a publisher and are pushed to a variable number of subscribers who have subscribed to the service. The pattern provides loose coupling by disconnecting the publishers from its subscribers commonly over the form of a queue.

SignalR is an asynchronous signalling library for ASP.NET which provides a framework for broadcasting messages to multiple clients when a given operation on the server is executed, providing a publish / subscription model with the subscribers being either a .NET client application or a web page. SignalR can be used to keep a number of web clients in sync with each other at real time with data held on the server. SignalR achieves this by holding open both the client and server side connections, ensuring the connection always stays open. When a message is sent from a client to the server the server side operation can broadcast a response to all clients by sending a callback to all the open client connections.

SignalR provides a far more efficient solution than simply making a client continuously poll the server on a set timer to check for any change to the state held on the the server and keep itself in sync. SignalR provides an architecture for pushing messages to listening clients rather than having each client individually responsible for pulling messages from the server. This can dramatically reduce the load on the server ensuring there are no needless requests repeatedly being sent from clients.

The real beauty of SignalR is in its simplicity. Requests are sent direct from a web view using JavaScript to the server, and responses are received via a callback on an open connection. This means that SignalR can be used with frameworks such as Knockout.js for easily keeping the UI refreshed with the latest data.

I am sure you can already think of a number of situations where this can be very useful. Such examples could include either an online chat application or a real time booking system. However I found that SignalR was the answer to a problem I had been looking to solve for a while. I am currently working on a large web based integration project for placing insurance quotes online. For a single request that is submitted for a quote, that request can be sent to multiple third party endpoints for processing. All requests are sent asynchronously from the client to the server. Within the application I have a health check routine, which monitors the status of these endpoints. I want to use SignalR to broadcast a message informing the user of the status of a given service within a footer on the application. This will inform the customer who may be waiting on an insurance quote if a service ever goes offline. This will also be very useful during development.

Lets walk through how this could be accomplished by creating a server side endpoint that will be responsible for receiving a request from a client, change a data object and then be responsible for issuing a response with that change to multiple clients.

First create a new ASP.NET MVC 3 web application. To add SignalR to this solution you can issue the following NuGet command in the package manager console within Visual Studio.

Install-Package SignalR

This will download and add the following scripts to your solution.

  • Scripts/jquery-1.6.4.js
  • Scripts/jquery.signalR.js

plus minimised versions of both scripts.

It will also add a assembly reference to SignalR.dll in your project

There are two options for implementing SignalR server-side. Both options involve deriving a class from an object within the SignalR framework. The two options are persistent connections and hubs. So what is the difference I hear you ask? Well let’s take a quick look at both.

A persistent connection endpoint is exposed as an IHttpHandler. This allows the endpoint to be accessed over HTTP, however in order to do so you must add a custom route map into the route map collection within the web applications global.asax. Deriving from a PersistentConnection enables the ability to override a number of set operations within the SignalR framework to receive client requests and broadcast responses.

The other option is to use a hub. A hub provides the ability to send different types of messages between client and server. There is no need to create a custom route map when using hubs. All requests are routed through the /signalr/hubs route which is added by the SignalR framework to access the hubs. Hubs allow you to add any operations you like. In this example we are going to use Hubs.

The code below is a simple implementation of a hub, with two methods GetServiceState() and UpdateServiceState(), both of which are exposed over HTTP and can be called direct from JavaScript running in a browser. The code includes a static member variable called messages. This is a list of strings and it is static so that its state can be shared across all client instances. The intention of the first method GetServiceState is set the initial state on the client. It is called when the client first opens a connection to the hub. The single line of the method uses the Clients object, which is a dynamic object which represents all the connected clients. As this object is dynamic you can simply specify the name of the callback routine that the JavaScript clients will be listening on. This single line allows you to push the messages collection to all connected clients. The second method UpdateServiceState adds an item to the list and pushes it out to all clients. In this example the current date and time is added to the list.

public class HealthCheck : Hub
{
    public static List<string> messages = new List<string>();

    public void GetServiceState()
    {
        Clients.updateMessages(messages);
    }

    public void UpdateServiceState()
    {
        messages.Add(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"));

        Clients.updateMessages(messages);
    }
}

So now to set up the client. In the _Layout,cshtml within your MVC 3 project add a script reference to the SignalR JavaScript library that was downloaded and added to the scripts folder when SignalR was added to the solution with NuGet. Please note that SignalR requires jquery to also be enabled. Therefore you will need to add the following two references.

<script src="@Url.Content("~/Scripts/jquery-1.6.4.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.signalr.min.js")" type="text/javascript"></script>

In index.cshtml add the following code

<script src="/signalr/hubs" type="text/javascript"></script>
<script type="text/javascript">
    $(function () {
        // creates a proxy to the health check hub
        var healthCheckHub = $.connection.healthCheck;

        // handles the callback sent from the server
        healthCheckHub.updateMessages = function (data) {
            $("li").remove();

            $.each(data, function () {
                $('#messages').append('<li>' + this + '</li>');
            });
        };

        $("#trigger").click(function () {
            healthCheckHub.updateServiceState();
        });

        // Start the connection and request current state
        $.connection.hub.start(function () {
            healthCheckHub.getServiceState();
        });
    });
</script>

<ul id="messages"></ul>

<button type="button" id="trigger">Send request</button>

The code above creates a proxy reference to the health check hub, it registers a callback called updateMessages. This callback is the one that the dynamic Clients object makes reference to and broadcast messages on. An event handler is added for the button. This will call the UpdateServiceState method on the hub when the button is clicked. Finally a connection to the hub is made and the GetServiceState method is called to retrieve the initial server state when the page is first rendered.

To test open two browser tabs and navigate to the view in both. Now click on the Send request button in one of the tabs and you will find that the current date and time is displayed shortly afterwards. Now flip to the other tab and you’ll see that the date and time displayed in the first tab is also displayed. This is because when you clicked the button in the first tab, the hub was called, the current date and time was added to the messages collection and this collection was pushed out to all listening clients who have an open connection registered, in this case both of the tabs.

So this is pretty clever but not a very useful example, but none the less it shows demonstrates a lot of the required plumbing, as we have made a connection to the hub and have registered a callback so that when a message is added on the hub it can be picked up and displayed by any listening clients with an open connection.

As previously mentioned I have a server side process that periodically checks the status of a given set of services. To broadcast the latest status I need to broadcast a message to the clients from outside the hub.

SignalR provides exactly this functionality by allowing you to retrieve the currently connected clients for a given hub by calling Hub.GetClients where T is the hub you wish to retrieve the clients for.

public class HealthMonitor
{
    public void Check()
    {
        /*
         * code ommited for clarity, 
         * but some process running on say a timer
         * or scheduler returns the latest state of the 
         * services and updates the messages
         * property on the HealthCheck hub
         */

        dynamic clients = Hub.GetClients<HealthCheck>();
        clients.updateMessages(HealthCheck.Messages);
    }
}

The code above is a arbitrary piece of code which can be run on the server. It can however also broadcast a message to all the currently connected clients outside of the hub itself. The other code change I made was to change the messages field variable to a property so I can keep the same list in sync whether it is updated from a client or server request.

public class HealthCheck : Hub
{
    private static List<string> messages;

    public static List<String> Messages 
    { 
        get
        {
            if (messages == null)
            {
                messages = new List<string>();
            }

            return messages;
        }
        set
        {
           messages = value;
        }
    }

//remaining code ommited

Each request that is received within the hub also includes the callers context. This can be used to only broadcast a response to a specific client. SignalR also provides the functionality to alternatively broadcast a response to a group of subscribers.

It is worth pointing out that the client is not restricted to being an MVC view, it can also be a .NET client.

SignalR is open source framework hosted on github. I would strongly recommend having a look at the documentation on the github site.

You may also like...

2 Responses

  1. Erik Forbes says:

    Great post – this is exactly the sort of thing I’m looking for to build a project I’ve had in mind for a while. Talk about good timing! =)

  2. Donny V says:

    Nice and simple tutorial and easy to read. Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">