SignalR 2

Well it’s about time I revisited SignalR. I’m working on a little side project to act as a intranet dashboard for one of the applications I support.

The idea is to produce those commonly asked for pieces of information about the current state of the application, infrastructure etc. into a usable web page.

So first up I want a way to update the dashboard when changes are detected (or found when polling at specific periods) to the dashboard. As I have written something a little like this in the past with SignalR I thought it’d be good to see where the technology stood now.

So we’re going to create a bare minimum ASP.NET MVC application with SignalR periodically causing updates to the page – ofcourse there’s plenty of chat samples for this, so if you’re looking for something a little more in depth, please go and check those out.

Getting started

I’m using Visual Studio 2015 and will be creating an ASP.NET MVC5 web application for this (ofcourse you don’t need to got full ASP.NET MVC for this, but I want to integrate this into my MVC app).

  • Create a new project in VS2015, select Visual C#/Web/ASP.NET Application (available as a .NET 4.5 or above template) – my project is called SignalRTest
  • After you press OK, select MVC from the next screen and press OK
  • Add a new folder named Hubs (not required but keeps the code partitioned nicely)
  • Right mouse click on the Hubs folder and select Add | New Item
  • Select Visual C#/Web/SignalR
  • Select SignalR Hub Class (v2) and give it a meaningful name, mine is ServerStatusHub
  • If you have a Startup.cs file (this will be supplied if you have authorization enabled), then simple add the following line to the Configuration method
    app.MapSignalR();
    
  • If you chose no authentication then you’ll need to create a Startup.cs file in the root folder (alongside the Web.Config in your solution), it should look like this
    using Microsoft.Owin;
    using Owin;
    
    [assembly: OwinStartupAttribute(typeof(SignalRTest.Startup))]
    namespace SignalRTest
    {
        public partial class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                app.MapSignalR();
            }
        }
    }
    

Let’s pause and take stock, we now have a Hub derived object named ServerStatusHub which will be callable from JavaScript (in the application we’re writing) and will equally be able to call out to client JavaScript code as and when server updates come in.

We’re going to change the code in the hub to this

using System;
using System.Threading;
using Microsoft.AspNet.SignalR;

namespace SignalRTest.Hubs
{
    public class ServerStatusHub : Hub
    {
        private readonly Timer timer;

        public ServerStatusHub()
        {
            timer = new Timer(state => Refresh());
            timer.Change(TimeSpan.FromSeconds(10), 
               TimeSpan.FromSeconds(30));
        }

        public void Refresh()
        {
            Clients.All.refresh(DateTime.Now.ToString());
        }
   }
}

Note: this is not great code as the timer will just keep going until the application closes.

So this will both simulate the equivalent of events coming from some external trigger (in this case the timer) which will be received and processed on the web application (client) and it also allows the code to be called as a server to initiate a refresh of the status, i.e. via a button click (for example).

Open the Index.cshtml file in the Views/Home folder of the solution and remove all the divs leaving the following

@{
    ViewBag.Title = "Home Page";
}

Now add to the Index.cshtml, the following

<div>
    <div id="serverStatus"></div>
</div>
<button id="serverRefresh">Refresh</button>

@section scripts {
    <script src="~/Scripts/jquery.signalR-2.1.2.min.js"></script>
    <script src="~/signalr/hubs"></script>
    <script>
        $(function() {

            try {
                var serverStatus = $.connection.serverStatusHub;

                serverStatus.client.refresh = function(status) {
                    $('#serverStatus').html(htmlEncode(status));
                };

                $('#serverRefresh')
                    .click(function() {
                        serverStatus.server.refresh();
                    });

            } catch (sourceError) {
                $('#serverStatus').html(htmlEncode(sourceError.message));
            }

            $.connection.hub.start()
                .done(function() {
                })
                .fail(function() {
                    $('#serverStatus').html('Failed to start server hub');
                });
        });

        function htmlEncode(value) {
            return $('<div />').text(value).html();
        }
    </script>
}

Don’t worry about the blue squiggle line say thar ~/signalr/hibs could not be found, the proxies will created when the application runs. If you do want to see what’s created you can run the application and navigate to the folder (i.e. http://localhost:56433/signalr/hubs) and see the proxies.

So we’re creating the SignalR JavaScript code against the proxies and hence have an object named serverStatusHub.

Whilst the methods and types are Pascal case in the C# code we use Camel case for the JavaScript.

The code above simply creates a connection to the server status hub and then we create a client method (equivalent to a callback) where we’ll recieve updates from the hub as they come in. We’ll simply output these to the HTML page.

We also hook up to the button serverRefresh so the user can call the hub to get the latest status of the servers in our imaginary application. The rest of this section of code is error handling code, but it’s following (after the catch block) with the code to connect to the hub and start the SignalR hub up.

And that’s all there is to it.