Who is Online with SignalR – A sample project

After having watched the build 2012 demo of signalR put on by Damian Edwards and David Fowler I have been nearly obsessed with playing with SignalR. Personally I feel like this will be one of those technologies that will open up a lot of new possibilities for web applications. I highly recommend you watch the talk I linked to above. Additionally SignalR as of now is 100% support by microsoft and has a home now on asp.net at www.asp.net/signalr.

This post is sharing some code I was just playing around with I might integrate into my web projects at some point. I have found it really useful to see who is currently online and a little information about what page they are on, browser, etc. A live chat application I have used in the past did this nicely (www.providesupport.com). As an eCommerce developer it is interesting to see how people progress through checkout or visually see how long they stay on your site. SignalR makes something like this painfully easy to implement.

There are many many chat program examples on the net, so I’m going to build off of of the chat example on their site. The information I want to see in real time: The users session id (a fictitious random number in this example), the user agent, their IP, and current page. I also will have two pieces, the user side which is the SignalR chat sample essentially. There is also an admin side which shows who is online. This is just some sample code you can modify however you see fit.

Here is the chat sample with a slight modification, I am passing in some information from the browser directly to the Join method. It is worth noting some of this information is available in the HTTP header, but I found that it wasn’t reliably sending when testing.

<script type="text/javascript" src="~/Scripts/jquery.cookie.js"></script>
<script type="text/javascript" src="/Scripts/jquery.signalR-1.0.0-alpha2.min.js"></script>
<!--  If this is an MVC project then use the following --> 
<!--  <script src="~/signalr/hubs" type="text/javascript"></script> -->
<script type="text/javascript" src="~/signalr/hubs"></script><script type="text/javascript">
        $(function() {
            // Proxy created on the fly          
            var chat = $.connection.chat;
 
            // Declare a function on the chat hub so the server can invoke it          
            chat.client.addMessage = function(message) {
                $('#messages').append('
	<li>' + message + '</li>');
            };
 
            $("#broadcast").click(function() {
                // Call the chat method on the server
                chat.server.send($('#msg').val());
            });
 
            // Start the connection
            $.connection.hub.start().done(function() {
                var sid = $.cookie('sid');
                chat.server.join({ Sid: sid, UserAgent: navigator.userAgent, Referer: document.referrer, CurrentPage: document.URL });
            });
        });
 
</script>

On the admin side there is some slightly different code. We don’t really care to see chat messages (we could), but instead we want to see who is online. Once the page loads and the connection is established the server sends the list of users to the page. If a new user joins or disconnects show connected is called which updates the list.

    <script src="~/Scripts/jquery.cookie.js"></script>
    <script src="/Scripts/jquery.signalR-1.0.0-alpha2.min.js" type="text/javascript"></script>
    <script src="~/signalr/hubs" type="text/javascript"></script>
    <script type="text/javascript">
        $(function() {
            // Proxy created on the fly          
            var chat = $.connection.chat;
 
            // Declare a function on the chat hub so the server can invoke it          
            chat.client.showConnected = function (message) {
                $('#messages').empty();
                $.each(message, function(index,value) {
                    $('#messages').append('<li>' + value.Sid + ' - ' + value.CurrentPage + ' - ' + value.UserAgent +' - '+ value.Connected + '</li>');
                });
            };
 
            // Start the connection
            $.connection.hub.start().done(function() {
                var sid = $.cookie('sid');
                chat.server.adminJoin().done(function() {
                    chat.server.getUsers();
                });
            });
        });
    </script>

Finally, here is the code for the hub which orchestrates everything. The UserList holds the current list of users in memory. This could easily be a database if you wanted. When an admin joins they are added to the admin group. The groups feature is part of SignalR and makes it really easy to keep groups of users separated. The UserList can be whatever you want, it could hold more or less information about your connected users.

using System;
using System.Diagnostics;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.AspNet.SignalR;
using System.Collections.Concurrent;
 
namespace SignalRHubs.Hubs
{
    public class Chat : Hub
    {
        public static ConcurrentDictionary<string, UserData> UserList = new ConcurrentDictionary<string, UserData>();
 
        public override Task OnDisconnected()
        {
            UserData Value;
            UserList.TryRemove(Context.ConnectionId,out Value);
 
            return Clients.Group("admins").showConnected(UserList); 
        }
 
        public void Send(string message)
        {
            // Call the addMessage method on all clients            
            Clients.All.addMessage(message);
        }
 
        public void AdminJoin()
        {
            Groups.Add(Context.ConnectionId, "admins");
        }
 
        public void GetUsers()
        {
            Clients.Group("admins").showConnected(UserList); 
        }
 
        public void Join(UserData data)
        {
            data.Connected = DateTime.Now.ToString("f");
            data.Ip = Context.ServerVariables["REMOTE_ADDR"];
            UserList.TryAdd(Context.ConnectionId, data);
            Clients.Group("admins").showConnected(UserList);
        }
    }
 
    public class UserData
    {
        public string UserAgent { get; set; }
        public int Sid { get; set; }
        public string Connected { get; set; }
        public string Ip { get; set; }
        public string Refer { get; set; }
        public string CurrentPage { get; set; }
 
    }
}

Here is the final result. When new users connect they are shown in /Home/Admin.
signalr

Here is the source code for the project. Note you will need to run the nuget command below to restore all of the packages.

nuget install packages.config

SignalRHubs

Tagged: , , ,