Background

Recently, while working on a project, I stumbled upon a requirement to implement some sort a notification or alert mechanism in a web application. Due to the criticality of performance factors, the final solution would have to be implemented in such a way that it must not consume much server/client resources itself. Without having another thought I decided to try and implement a push based notification mechanism that can send messages to all the connected client as and when required.

What is SignalR?

SignalR is a library from Microsoft that can be easily integrated into any ASP.NET application targeting .NET Framework 3.5+. The library provides easy to integrate interfaces for implementing a push-based notification server and its consumers. The library exposes both high-level and low-level APIs which makes it flexible enough to be used in different kinds of scenarios. You can communicate with a SignalR server through JQuery, .NET based console applications, windows services, desktop applications & WPF applications. This library makes it vert easy to implement any real-time functionality in a web application that needs to send messages to connected clients without implementing any sort of polling mechanism. For communication, the library uses WebSockets wherever available and falls back to other standard communication techniques if it finds that WebSockets aren’t supported. For further details about the library, go to this link.

Implementing the Notification Server

You can easily create a notification server by using Hubs which is a way to implement a listener class in your web application. The Hub class hides all the low level connection management detail and exposes useful, high-level properties and functions to make your life easier. I’ll be creating an MVC 4 application but it should work with MVC 3 as well.

Open the Visual Studio (I am using 2012 express edition for Web) and create a new MVC 4 project. On the project template dialog, select Basic. After the project is created, right click on References (in Solution Explorer) and select ‘Manage NuGet Pacakges’. In package manager window select online from left and search SignalR. Refer to the image below:

manage-nuget

You’ll have to install Microsoft ASP.NET SignalR into your project as shown. The package manager will install all the related dependencies as well.

Now, create a new folder in your MVC application and name it Hubs and create a new class in that folder. You can name the class any way you like but it should inherit from Hub class. I am naming it NotificationHub. The full implementation of the class is as seen below:

notification-hub

Here, I have created one method for registering a client on its request. I am doing it this way so that server knows where to send a message in response. The class is also maintaining a collection of all the connected clients for use later on. I have also added an AddNotification method taking message and username as parameters so that the server knows which user to send message to. The AddNotification method can be called from any other client which needs to notify the web application’s clients about some event.
Also take a note of this statement –  Clients.Caller.addMessage(“‘” + userName + “‘ registered.”). The Caller property is dynamic type and the addMessage is actually a client method that the server is trying to call through SignalR interfaces. The method will be implemented in the web client through JQuery in next section.

Implementing a JQuery/JS Client

In your MVC application, add a new controller. The controller just needs to implement a single action method for this demo. Here I have created an Index action that is not doing anything but just calling its view.

Now add a view for the action that you have just created. Add the following code in your view.

@{

ViewBag.Title = “Index”;

}

<script src=”@Url.Content(“~/signalr/hubs”)” type=”text/javascript”></script>

<!–  Following scripts are created dynamically at runt –>

<script src=”~/signalr/hubs” type=”text/javascript”></script>

<script type=”text/javascript”>

$(function () {

$(“#sendControls”).hide(“fast”);

// Proxy created on the fly

var notificationHub = $.connection.notificationHub;

// Declare a function on the hub so the server can invoke it

notificationHub.client.addMessage = function (message) {

$(‘#messages’).append(“<li>” + message + “</li>”);

};

// Start the connection

$.connection.hub.start().done(function () {

$(“#register”).click(function () {

// Register client.

notificationHub.server.registerClient($(“#user”).val());

$(“#registration”).hide(“fast”);

$(“#sendControls”).show(“fast”);

});

$(“#send”).click(function () {

// Call the method on the server

notificationHub.server.addNotification($(“#msg”).val(), $(“#toUsr”).val());

});

});

});

</script>

<div>

<div id=”registration”>

<label>Username: </label>

<input type=”text” id=”user” />

<input type=”button” id=”register” value=”Register” /><br />

</div>

<div id=”sendControls”>

<label>To (Username): </label>

<input type=”text” id=”toUsr” /><br />

<label>Message (Username): </label>

<input type=”text” id=”msg” />

<input type=”button” id=”send” value=”Send” />

</div>

<ul id=”messages”>

</ul>

</div>

Some of the scripts that provide communication interfaces are generated dynamically. See the following script include:

<script src=”~/signalr/hubs” type=”text/javascript”></script>

You’ll also have to include the signalR js file (jquery.signalR-1.1.0.min.js) in order for the client to work properly.

The client creation steps are straight forward. First, you have to get the instance of the server hub which is done through the following statement:

var notificationHub = $.connection.notificationHub;

This line actually creates a Hub Proxy (see SignalR documentation to find out more about it). Since I named my server hub class as NotificationHub, the above statement uses $.connection.notificationHub. If your class name is Abc then you should use $.connection.abc (notice the change in first letter case of class name). After getting the instance of proxy, you’ll have to register all the client methods that you want your server to interact with. Here I have added only one method called addMessage. After that, you’ll need to start the hub connection. SignalR also exposes a done event which helps in registering a callback when the client has successfully established the connection to server. In that event, I have written a statement which is calling the server’s RegisterClient method. Notice how the case of the functions has changed to ‘registerClient’ instead of ‘RegisterClient’.

Here you go, you have written a client that can now interact with server by calling a method in the hub class. Also the server is able to call the client’s JS method whenever it wants.

To test the output, run the application. Enter a user name to register and click register. Open your application link in another browser window, type another username and click register. Now you can communicate between the two client application using the provided input controls. Each client window calls the Hub’s method at server and that method in return pushes some message to another client window by calling a JavaScript function at the client side. See the screenshot below.

running-app

Implementing a .Net Client

The .NET client application is similar to what we have done in the JQuery/JS client. I have created the following helper class that can easily be integrated to any .NET based client that needs to call a SignalR based Hub.

class NotificationClient

{

HubConnection _connection;

IHubProxy _proxy;

public bool IsConnectionOpen { get; set; }

public NotificationClient(string url, string hubName)

{

_connection = new HubConnection(url);

_proxy = _connection.CreateHubProxy(hubName);

}

public void AddClientMethod(string methodName, Action method)

{

if (IsConnectionOpen)

throw new InvalidOperationException(“Client methods cannot be added after a hub connection has been opened.”);

_proxy.On(methodName, method);

}

public void AddClientMethod<T1>(string methodName, Action<T1> method)

{

if (IsConnectionOpen)

throw new InvalidOperationException(“Client methods cannot be added after a hub connection has been opened.”);

_proxy.On(methodName, method);

}

public void AddClientMethod<T1, T2>(string methodName, Action<T1, T2> method)

{

if (IsConnectionOpen)

throw new InvalidOperationException(“Client methods cannot be added after a hub connection has been opened.”);

_proxy.On(methodName, method);

}

public void AddClientMethod<T1, T2, T3>(string methodName, Action<T1, T2, T3> method)

{

if (IsConnectionOpen)

throw new InvalidOperationException(“Client methods cannot be added after a hub connection has been opened.”);

_proxy.On(methodName, method);

}

public void AddClientMethod<T1, T2, T3, T4>(string methodName, Action<T1, T2, T3, T4> method)

{

if (IsConnectionOpen)

throw new InvalidOperationException(“Client methods cannot be added after a hub connection has been opened.”);

_proxy.On(methodName, method);

}

public void AddClientMethod<T1, T2, T3, T4, T5>(string methodName, Action<T1, T2, T3, T4, T5> method)

{

if (IsConnectionOpen)

throw new InvalidOperationException(“Client methods cannot be added after a hub connection has been opened.”);

_proxy.On(methodName, method);

}

public void AddClientMethod<T1, T2, T3, T4, T5, T6>(string methodName, Action<T1, T2, T3, T4, T5, T6> method)

{

if (IsConnectionOpen)

throw new InvalidOperationException(“Client methods cannot be added after a hub connection has been opened.”);

_proxy.On(methodName, method);

}

public void AddClientMethod<T1, T2, T3, T4, T5, T6, T7>(string methodName, Action<T1, T2, T3, T4, T5, T6, T7> method)

{

if (IsConnectionOpen)

throw new InvalidOperationException(“Client methods cannot be added after a hub connection has been opened.”);

_proxy.On(methodName, method);

}

public void CallServerMethod(string methodName, params object[] parameters)

{

if (!IsConnectionOpen)

throw new InvalidOperationException(“Hub connection must be opened before calling a server method.”);

_proxy.Invoke(methodName, parameters);

}

public T CallServerMethod<T>(string methodName, params object[] parameters)

{

if (!IsConnectionOpen)

throw new InvalidOperationException(“Hub connection must be opened before calling a server method.”);

return _proxy.Invoke<T>(methodName, parameters).Result;

}

public void OpenConnection()

{

_connection.Start().Wait();

IsConnectionOpen = true;

}

}

It is very easy to use the class in order to communicate with the SignalR Hub. See the following code:

NotificationClient client = new NotificationClient(“http://localhost/Notifications&#8221;, “NotificationHub”);
client.CallServerMethod(“AddNotification”, “Message”, “username”);

As you can see, implementing a real-time RPC calls from server-to-client and client-to-server becomes very much easier using SignalR library. The library is getting mature and current release is very much stable and provides enough funtionality for these type of scenarios.