Scott Smith

Blog Tutorials Projects Speaking RSS

SignalR: Awesome Real-Time With .NET

Welcome to part one of the series SignalR: Awesome Real-Time with .NET

Part 1 - SignalR: Awesome Real-Time with .NET

Part 2 - SignalR: Awesome Real-Time with .NET - Part 2

What is SignalR?

SignalR is an async signaling library for .NET to help build real-time, multi-user interactive web applications

Or…

A real cool .NET framework hosted in ASP.NET and a JavaScript library (on the client side that helps build collaborative web apps quickly and painlessly. It is open source and freely available on GitHub.

And…

It doesn’t have to be hosted in ASP.NET. It can also be hosted using OWIN (Open Web Interface for .NET) or self host (console, windows service, azure, etc.).

A JavaScript library isn’t the only client side implementation as well. As of today, there are jQuery, Native .NET, WP7, iOS, Silverlight, WinRT, and Android (via Mono) implementations.

What does it solve?

Pushing data from the server to the client (not just browser clients) has always been a tough problem. SignalR makes it dead easy and handles all the heavy lifting for you.

SignalR abstracts the raw technique of keeping connections open between a client and a server. SignalR uses a fallback mechanism to connect the browser to the server. After an initial negotiation request the following transports are tried in order until a successful connection can be made: WebSockets, Server Sent Events (EventSource), Forever Frame, or Ajax long polling.

Implementations

There are two choices when developing with SignalR, PersistentConnections and Hubs.

PersistentConnections - A PersistentConnection is the base class that has an api for exposing a SignalR service over http.

Hubs - Hubs provide a higher level RPC framework over a PersistentConnection. If you have different types of messages that you want to send between server and client then hubs is recommended so you don’t have to do your own dispatching.

For this article and tutorial, we will be focusing on Hubs.

Time to Code

For this tutorial, we will be using Visual Studio 2012 with ASP.NET MVC 4.

Step 1 - Create an empty ASP.NET MVC 4 web application

File -> New Project -> Web -> ASP.NET MVC 4 Web Application. Call your project anything you like. I used SignalRTutorial .

Step 2 - Add the SignalR package via NuGet

Right click on the newly created project (in my case it is called SignalRTutorial) and click Manage NuGet Packages. Search online for SignalR and click install for the package named SignalR. It will automatically add all needed dependencies for you.

Step 3 - Create the Home Controller

Right click on the folder labeled Controllers and select Add -> Controller. Name it HomeController and make sure the “Empty MVC controller” template is selected.

Step 4 - Create the Index view for the Home Controller

In the newly created HomeController.cs class, right click the Index method and select “Add View”. Be sure to uncheck “Use a layout or master page” but leave everything else alone.

Step 5 - Make sure everything is working

Take a moment to make sure your project builds and run it using Ctrl-F5. You should see the web page open with nothing on the page. This is a good thing.

Step 6 - Create a simple SignalR Hub

Create a folder in your MVC 4 project called Hubs. This is just for organization and clarity. You are not required to have your hubs inside a folder called Hubs.

Create a class called TagHub inside the Hubs folder. Make sure to have your class inherit from SignalR.Hubs.Hub. This will allow SignalR to work its magic.

using System.Collections.Generic;
using SignalR.Hubs;

namespace SignalRTutorial.Hubs
{
    public class TagHub : Hub
    {
        static List _tags = new List();

        static TagHub()
        {
            _tags.Add("c#");
            _tags.Add(".NET");
            _tags.Add("SignalR");
        }

        public void getTags()
        {
            //Call the initTags method on the calling client
            Caller.initTags(_tags);
        }
    }
}

Step 7 - Update your Index view for the Home Controller

Open Index.cshtml that was created earlier and modify it to the following code.

@{
Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="~/Scripts/jquery-1.6.4.js"></script>
    <script src="~/Scripts/jquery.signalR-0.5.3.js"></script>
    <script src="/SignalR/Hubs"></script>
</head>
<body>
    <ul id="tags"></ul>

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

            tagHub.initTags = function (tags) {
                $.each(tags, function (index, value) {
                    $('#tags').append('<li>' + value + '</li>');
                });
            };

            $.connection.hub.start()
                .done(function () {
                    tagHub.getTags();
                })
                .fail(function () {
                    alert("Could not Connect!");
                });
        });
    </script>
</body>
</html>

Step 8 - Run the project and see what happens

So what exactly is going on here?

The Caller property in our Hub is provided by SignalR as part of the Hub class definition. This is a  dynamic object that you can use to invoke a client side method written in JavaScript on the connection making the call to getTags. SignalR does the plumbing using web sockets, long polling, or what ever, and we don’t care. SignalR also generates a client side proxy hub to invoke methods in our TagHub. For example, using the client side proxy hub our client invokes the getTags method in the above Hub during initialization, the client invoking the getTags method (Caller) will get a callback to it’s initTags JavaScript method, with all the existing tags.

So the order of events are:

  1. Page loads
  2. Client side
    1. var tagHub = $.connection.tagHub;
      1. Generates a client side proxy hub to our TagHub object
    2. $.connection.hub.start();
      1. Starts our connection to the hubs
    3. tagHub.getTags();
      1. Calls the getTags() method on the server side TabHub object
  3. Server side
    1. Caller.initTags(_tags);
      1. Calls the initTags(tags) method on the client side

Step 9 - Supporting Clients on our Hub

We will now add support to our Tag web application to allow adding new tags. The one thing we want though is for all connected clients to have their list of tags updated when new ones are added.

Add the following method to your TagHub class:

public void setTag(string tag)
{
    //Add the new tag to the list of tags
    _tags.Add(tag);

    //Call the addTag method on all connected clients
    Clients.addTag(tag);
}

Add the following HTML just above the unordered list showing the list of tags:

<div>
    <input id="newTagText" type="text" placeholder="Enter a new tag" />
    <input id="newTagSubmit" type="submit" value="Add new tag" />
</div>

Finally add the following methods to your JavaScript:

tagHub.addTag = function (tag) {
    $('#tags').append('<li>' + tag + '</li>');
};

$('#newTagSubmit').click(function () {
    var tag = $('#newTagText').attr('value');
    tagHub.setTag(tag);
});

Step 10 - Run the project again, open the page in more than one window, and add tags

So what exactly is going on here?

The Clients property in our Hub is provided by SignalR as part of the Hub class definition. This is a  dynamic object that you can use to invoke a client side method written in JavaScript on all connected clients. Using the client side proxy hub our client invokes the setTags method in the TagHub, all connected clients will get a callback to it’s addTags JavaScript method, with the new tag.

So the order of events are:

  1. Page loads
  2. Client side
    1. var tagHub = $.connection.tagHub;
      1. Generates a client side proxy hub to our TagHub object
    2. $.connection.hub.start();
      1. Starts our connection to the hubs
    3. tagHub.setTag(tag);
      1. Calls the setTag() method on the server side TagHub object
  3. Server side
    1. Clients.addTag(tag);
      1. Calls the addTags(tag) method on all connected clients (client side)

Conclusion

That is it for now! With very little code, effort, and complexity we were able to implement a collaborative web application.

The final source code can be found GitHub.

Further reading

SignalR official documentation

ASP.NET MVC, SignalR and Knockout…

signalr tutorial with knockoutjs

Testing SignalR Connections with NUnit