Push notification from server to client using SignalR

There are number of scenarios where we need send push notification from server to client, client gets update from the server when ever server has new data.

Some of the scenario which benefit from push notification(real-time web) are

  • Monitoring Server application over the web(Diagnostic reports or Error reports )
  • User signup notification.
  • Stock tickers.
  • Chat application.
  • Monitoring of hardware instruments.

Now we know the possible usecases ,so how can we implement server to send arbitrary data to client.

Currently there are four established technique to do push notification on web

    • Polling : In case of polling Web browser make connection to server, server responds immediately with data if present else empty response. After predefined time(polling time) Web browser makes same request to server.This process repeats. Even though this solution works, it is not scalable solution. It can put heavy load on the server depending on the polling interval and number of clients . Polling from JavaScript shown below
	function getInfo() {

	$.ajax("url", function ( newInfo){
		if ( newInfo != null) {
			// do something with the data
		}
	});
	// poll again after 20 seconds
	setTimeout(getInfo,20000);
}
// start the polling loop
getInfo();
    • Long polling: It is similar to polling , where Web browser makes request to server , but server does not respond to client immediately , it will leave the request hanging open till it has some data to deliver. Eventually server responds and client uses the data and starts new request, whole process repeats. This technique is improvement over polling as it does creates unnecessary connections.  Long polling from JavaScript shown below
function getNewInfo(){
  $.ajax("url", function (newinfo) {
      // do something with the data
	  // start the new request
      getNewINfo();
  });
}
// start the polling loop
getNewInfo();
  • EventSource: It is similar to long polling client make request ,server leaves the request hanging open till it has some data to deliver, difference is after sending data back server does not close the connection. Server will keep the connection open .  This solution provide good scalability in handling requests , also it is implemented in natively by Web Browser it can perform better compared to previous techniques.But EventSource is  not iimplemented IE.  Event source from JavaScript shown below
var eventSrc = new EventSource("url");
	// register event handler for the message
    eventSrc.addEventListener( "message",function (evt) {
        //process the data
    });
  • WebSocket:Is the new approach to Web browser/server communication. It is bidirectional communication channel compared to unidirectional Event Source.  At high-level client sends HTTP Connection with “Upgrade: websockets” header;server leaves connection open , client and server negotiate which version of web socket protocol to use. Client and Server exchange messages once connection is upgraded to web socket. This technique is natively implemented by the Web Browser/Server . Refer to caniuse website to check the latest websocket implementation in Web Browser. WebSocket usage from JavaScript shown below
var socket = new WebSocket("url");
socket.onmessage = function (msg) {
	var newInfo = msg.data;
	// do something with the data
}
// client can also send request to server
socket.send(.... )

As we seen ,each technique has some pros and cons and not all browser have implemented all the features.
What we need is some abstraction over the different implementation  so that developer need not worry about various implementations.

SignalR to rescue.

SignalR is an abstraction on top of a persistent HTTP connection. It provides on consistent API over different implementations(long polling,websocket).

SignalR can use websocket if it is implemented by the Web browser and server and fallback to long polling if it is not implemented.
SignalR uses C# dynamic feature on the server side ( asp.net ) and Javascript dynamic features on the client side to create server and client proxy.

It is similar to Nodejs+socket.io implementation based on JavaScript.

CPU usage monitor sample

To illustrate the SignalR usage I wrote sample web application which allows to monitor % cpu usage on the server in real-time. Sample  application uses SignalR on server/client and Google web chart  for visualization.

Tools used: Free Microsoft Visual Web Developer 2010 Express, SignalR on Nuget and Google Chart Tools.

Here is the step by step instruction.

1. Create “ASP.NET Empty Web Application” in VS Web Developer express.

2. Use Nuget Package manager console in VS to install SignalR and associated dependency from Nuget.

3.Create class to hold the cpu usage information.

public class CpuUsageInfo
    {
        public double CPUUsage { get; set; }
        public String DateString { get; set; }
    }

4. Create new class on the server side which derives from SignalR PersistentConnection class.

 public class Perfmon : PersistentConnection
    {
        protected override System.Threading.Tasks.Task OnConnectedAsync(SignalR.Hosting.IRequest request, IEnumerable groups, string connectionId)
        {
            return base.OnConnectedAsync(request, groups, connectionId);
        }
    }

5.Update the Global.asax file to map ASP.NET route

protected void Application_Start(object sender, EventArgs e)
        {

            // add routing
            RouteTable.Routes.MapConnection("perfmon", "perfmon/{*operations}");

            Task.Factory.StartNew(() =>
                {
                    // get connection to global client connections
                    IConnectionManager connectonManager = AspNetHost.DependencyResolver.Resolve();
                    var connection = connectonManager.GetConnection();

                    var counter = new PerformanceCounter();
                    counter.CategoryName = "Processor";
                    counter.CounterName = "% Processor Time";
                    counter.InstanceName = "_Total";

                    while (true)
                    {
                        var item = new CpuUsageInfo()
                        {
                            DateString = DateTime.Now.ToString("hh:mm:ss"),
                            CPUUsage = Math.Round(counter.NextValue(), 2),
                        };

                        connection.Broadcast(item);

                        Thread.Sleep(500);
                    }
            });

        }

6. Inside Application_Start method add code to get send CPU usage events to connected clients using SignalR library.

7. Create new html file with that plots line chart using Google charting tools. In the JavaScript make connection to server using SignalR js library. As the data arrives from the server update the chart data collection and redraw the chart.

    var output;
    $(document).ready(function () {

        output = $("#output");

    });

    var data;
    var chart;
    var options;
    // Load the Visualization API and the piechart package.
    google.load('visualization', '1.0', { 'packages': ['corechart'] });
    // Set a callback to run when the Google Visualization API is loaded.
    google.setOnLoadCallback(drawChart);
    // Callback that creates and populates a data table,
    // instantiates the pie chart, passes in the data and
    // draws it.
    function drawChart() {

        // Create the data table.
        data = new google.visualization.DataTable();
        data.addColumn('string', 'Time');
        data.addColumn('number', 'CPU Usage in %');

        // Set chart options
        options = { 'title': 'CPU usage history', 'width': 600, 'height': 400 };

        // Instantiate and draw our chart, passing in some options.
        chart = new google.visualization.LineChart(document.getElementById('chart_div'));
        chart.draw(data, options);
    }

    connection = $.connection('/perfmon');

    connection.received(function (dataItem) {
        var newItem = dataItem;

        output.text("Received text from the server .: " + newItem.DateString + "," + newItem.CPUUsage);

        // update chart with data received from the server
        data.addRow([newItem.DateString, newItem.CPUUsage]);
        if (data.getNumberOfRows() > 100) {
            data.removeRow(0);
        }
        chart.draw(data, options);
    });

    connection.start();

Here is the demo output in Browser

Complete sample code
Resources
1. SignalR Channel9 Video
2. SignalR on GitHub
3. Socket.IO

Advertisements

2 thoughts on “Push notification from server to client using SignalR

    • Hi Nahal
      Sample shown in the blogpost broadcast messages to all connected clients. Look at “connection.Broadcast(item)” call inside “Application_Start” function.

      If you are using latest version of SignalR you can use following code to broadcast to all connected clients

      public class MyEndPoint : PersistentConnection
      {
      protected override Task OnConnected(IRequest request, string connectionId)
      {
      return Connection.Broadcast(“Connection ” + connectionId + ” connected”);
      }
      }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s