Using Server Side Timers and SignalR in ASP.NET MVC Applications

I thought it would be fun to create an “Internet uptime” page that you can see live here on Azure Websites. It shows how long the Internet (since ARPANET) has been around for.

image

Creating a Class that can be Managed by ASP.NET

The HostingEnvironment.RegisterObject method can be used to register an instance of an object that has its lifetime managed by the hosting environment.

To register an object it must implement the IRegisteredObject interface.

This interface defines a Stop method which gets called when ASP.NET needs to shutdown the app domain.

So, in the application start we can create an instance of our class and register it:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);

    HostingEnvironment.RegisterObject(new BackgroundUptimeServerTimer());
}

Creating a SignalR Hub to Send Messages from the Server to Client

Next we create a SignalR hub and the HTML.

So the hub class is called UptimeHub:

public class UptimeHub : Hub
{
}

We can get the server to call a client JavaScript method called “internetUpTime” in the HTML page and have this client code display the what’s been sent from the server timer.

The following shows the complete HTML for the page. Notice the “hub.client.internetUpTime = function (time) …” this function will get executed every time our server timer event fires.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Internet Uptime</title>
    <link href='http://fonts.googleapis.com/css?family=Josefin+Sans' rel='stylesheet' type='text/css'>
    <style>
        body {
            background-color: black;
            color: white;
            margin: 0;
            padding: 0;
        }
         #message {
             font-family: 'Josefin Sans', sans-serif; 
             font-size: 7vh;
             text-align: center;
             height: 50vh;
             margin-top: 24vh;
         }
    </style>
</head>
<body>   
    <script src="Scripts/jquery-1.6.4.min.js"></script>
    <script src="Scripts/jquery.signalR-2.1.0.min.js"></script>
    <script src="/signalr/hubs"></script>
        
    <script>
        $(function() {
            var hub = $.connection.uptimeHub;

            $.connection.hub.start();

            hub.client.internetUpTime = function (time) {

                $('#message').text('');

                var arr = time.split(",");

                for (var i = 0; i < arr.length; i++) {
                    $('#message').append(arr[i]);

                    if (i < arr.length -1) {
                        $('#message').append('<br/>');
                    }
                }

                
            };
        });
    </script>

    <div id="message">please wait...</div>
</body>
</html>

Also notice in the preceding HTML the script reference to “/signalr/hubs”.

The code in the “internetUpTime” function takes the string sent from the server which contains something like “2 weeks, 3 days, 4 hours” and outputs each time component on a separate line in the browser by added a <br/> after each time component (except the last one). The split message is output into the div called “message”.

Check out the viewport relative font sizes as well.

Registering the SignalR Hub

To register the UptimeHub in Visual Studio 2013 we can add a new item called “OWIN Startup class” as seen in the following screenshot:

image

So we end up with the following class to register the SignalR hub:

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(Up.Hubs.Startup))]

namespace Up.Hubs
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

An Aside on Creating Humanized Timespans

The Humanizer library allows us to create more human-feeling applications. In the final background timer code that we’ll see in a moment we use it in a few ways. (Check out my Making .NET Data Types More Human With Humanizer Pluralsight course)

The first is to make use of its fluent TimeSpan, so to create a 2 second TimeSpan we can just write 2.Seconds().

The second is to call the Humanize method on a TimeSpan to get a string such as “2 weeks, 3 days, 4 hours”. When we call this method we can specify how many “units” we want – by default we’ll just get the largest, e.g. “2 weeks”.

We also create a DateTime fluently by writing: On.October.The29th.In(1969);

Implementing the IRegisteredObject BackgroundUptimeServerTimer Class

The complete listing for this class is shown below.

In the constructor we get a reference to UptimeHub and start the background timer.

Every second the BroadcastUptimeToClients method is called which in turn creates a humanized string and sends it to the clients (see the JavaScript above).

public class BackgroundUptimeServerTimer : IRegisteredObject
{
    private readonly DateTime _internetBirthDate = On.October.The29th.In(1969);
    private readonly IHubContext _uptimeHub;
    private Timer _timer;


    public BackgroundUptimeServerTimer()
    {
        _uptimeHub = GlobalHost.ConnectionManager.GetHubContext<UptimeHub>();

        StartTimer();
    }
    private void StartTimer()
    {
        var delayStartby = 2.Seconds();
        var repeatEvery = 1.Seconds();

        _timer = new Timer(BroadcastUptimeToClients, null, delayStartby, repeatEvery);
    }
    private void BroadcastUptimeToClients(object state)
    {
        TimeSpan uptime = DateTime.Now - _internetBirthDate;

        _uptimeHub.Clients.All.internetUpTime(uptime.Humanize(5));
    }
    
    public void Stop(bool immediate)
    {
        _timer.Dispose();

        HostingEnvironment.UnregisterObject(this);
    }
}

 

Publishing to Azure Websites

Now to publish this to Azure it’s simply a case of a few of clicks in Visual Studio which is very cool (I had already created the Website in Azure).

publishtoazure

 

…and a few seconds later the website is ready for the world to see as the following screenshot shows:

image

 

Check out the live site running on Azure

 

I found the following articles to be really useful:

SHARE:

Pingbacks and trackbacks (1)+

Add comment

Loading