As more and more applications and services are becoming always on and accessible from a wide range of devices it’s important that we are able to securely manage sessions for users across all of these systems.
Imagine that you have a web application that a user tends to stay logged into all day. Over time the application produces notifications for the user and those notifications should be shown fairly immediately. In this post I’m going to talk about a very important notification – when the user’s account has logged into another device while still logged into their existing session. If the user is logged into the application on their desktop at work it might be bad that they also just logged into their account from a computer on the other side of the country. Essentially, what we want is a way to notify the user that their account just logged in from another device. Why didn’t I just lead with that?
In the next few posts I’m going to show how we can build a real-time user notification and session management system for a web application.
To accomplish this task I’m going to use the SignalR library:
ASP.NET SignalR is a new library for ASP.NET developers that simplifies the process of adding real-time web functionality to your applications. Real-time web functionality is the ability to have server-side code push content to connected clients instantly as it becomes available.
Conceptually it’s exactly what we want to use – it allows us to notify a client (the user’s first browser session) from the server that another client (another browser or device) has logged in with the same account.
SignalR is based on a Remote Procedure Call (RPC) design pattern allowing messages to flow from the server to a client. The long and the short of it is that whenever a page is loaded in the browser a chunk of JavaScript is executed that calls back to the server and opens a connection either via websockets when supported or falls back to other methods like long polling or funky (but powerful) iframe business.
To understand how this works it’s necessary to get SignalR up and running. First, create a new web project of your choosing in Visual Studio and open the Nuget Package Manager. Search online for the package “Microsoft.AspNet.SignalR” and install it. For the sake of simplicity this will install the entire SignalR library. Down the road you may decide to trim the installed components down to only the requisite pieces.
Locate the global.asax file in your project and open it. In the Application_Start method add this bit of code:
RouteTable.Routes.MapHubs();
This will register a hub (something we’ll create in a minute) to the “~/signalr/hubs” route. Next open your MasterPage or View and add the following script references somewhere after a reference to jQuery:
You’ll notice the second script reference is the same as our route that was added earlier. This script is dynamically generated and provides us a proxy for communicating with the hub on the server side.
At this point we haven’t done much. All we’ve done is set up our web application to use SignalR. It doesn’t do anything yet. In order for communication to occur we need something called a Hub.
A hub is the thing that offers us that RPC mechanism. We call into it to send messages. It then sends the messages to the given recipients based on the connections opened by the client-side JavaScript. To create a hub all we need to do is create a new class and inherit from Microsoft.AspNet.SignalR.Hub. I’ve created one called NotificationHub.
public class NotificationHub : Hub { // Nothing to see here yet }
A hub is conceptually a connector between your browser and your server. When a message is sent from your browser it is received by a hub and the hub sends it off to a given recipient. A hub receives messages through methods defined by you.
Before digging into specifics a quick demo is in order. In our NotificationHub class let’s create a new method:
public void Hello(string message) { Debug.WriteLine(message); }
For now that’s all we have to write server-side for the sake of this demo. It will receive a message and it will write it to the debug stream. Next, go back to your page to write some HTML and JavaScript.
First create a <div> and give it an Id of connected:
<div id=”connected”></div>
Then add some JavaScript:
$.connection.hub.start().done(function () { $(‘#connected’).text(‘I’m connected with Id: ‘ + $.connection.hub.id); });
What this will do is open a proxy connection to the hub(s) and once it’s completed the connection dance, the proxy calls a function and sets the text to the Id of the proxy connection. This Id value is a unique identifier created every time the client connects back to the server.
Now that we have an open connection to our hub we can call our Hello method. To do this we need to get the proxy to our notification hub, which is done through the $.connectionobject.
var notifier = $.connection.notificationHub;
For each hub we create and map to a route, the connection object has a pointer to it’s equivalent JavaScript proxy. Mind the camel-casing though. Once we have our proxy we can call our method through the server property. This property maps functions to methods in the hub. So to call our Hello method in the hub we call this JavaScript:
notifier.server.hello(‘World!’);
Lets make that clickable.
<a id=”sayHi” href=”#”>Say Hello!</a> $(‘#sayHi’).click(function() { notifier.server.hello(‘World!’); });
If you click that you should now see “World!” in your Debug window.
That’s all fine and dandy for sending messages to the server, but AJAX already does that. Boring! Let’s go back to our hub and update that Hello method. Add the following line of code:
public void Hello(string message) { Clients.All.helloEveryone(message); }
What this will do is broadcast our message to All connected clients. It will call a function on the client named helloEveryone. For more information on who can receive messages take a look at the Hubs documentation. However, for our clients to receive that message we need to hook in a function for our proxy to call when it receives the broadcast. Back in the HTML and JavaScript add this:
<div id=”msg”></div> notifier.client.helloEveryone = function(message) { $(‘#msg’).text(message); }
We’ve hooked a function into the client object so that when the proxy receives the message to call the function, it will call our implementation. It’s really easy to build out a collection of calls to communicate both directions with this library. All calls that should be sent to the server should call notifier.server.{yourHubMethod} and all calls from the hub to the clients should be mapped to notifier.client.{eventListener}.
If you open a few browsers and click that link, all browsers should simultaneously receive the message and show “World!”. That’s pretty cool.
At this point we have nearly enough information to build out our session management and notification system. In the next post I’ll talk about how we can send messages directly to a specific user, as well as how to send messages from outside the scope of a hub.