Click here to Skip to main content
Click here to Skip to main content
Go to top

HTML5: Real-Time Push Notifications from .NET Application

, 5 May 2014
Rate this:
Please Sign up or sign in to vote.
Simple example for publish-subscribe scenario between HTML5 JavaScript and .NET without using polling or long-polling mechanism.

Introduction

The example bellow demonstrates a publish-subscribe communication scenario between JavaScript and a .NET application. The HTML5 JavaScript client needs to subscribe for an event (or more events) in the .NET application. When the event occurs the .NET application notifies subscribed clients.

The communication is realized via WebSockets (full-duplex single socket connection) and therefore it does not use a polling or long-polling mechanism which would be used in case of the HTTP protocol.

Notification messages are pushed from the service to all subscribed clients instantly when the event occurs.

Example Code

The example application is based on Eneter.Messaging.Framework the free lightweight cross-platform framework for the interprocess communication which is very easy to use.
The example also uses the Chart.js library. A nice free library for drawing charts.

To Run Example

  • Download and unzip this example.
  • Download Eneter for .NET from http://www.eneter.net/ProductDownload.htm.
  • Open the example project in Visual Studio and add the reference to Eneter.Messaging.Framework.dll that you downloaded.
  • Build the application and execute it.
  • Open index.html (from CpuUsageClient directory) in an internet browser.
  • Press 'Open Connection' button and then 'Subscribe' button.
  • Web-page starts to get notifications and the chart is displayed.

In order to demonstrate the publish-subscribe scenario between JavaScript and .NET the example bellow implements a simple .NET console application and a simple HTML5 web-page.
The console application regularly checks the CPU usage and notifies its value.
The HTML5 web-page subscribes to be notified about CPU usage. When it receives the notification it updates the value and displays the chart.

768473/PublishSubscribeBetweenJSNET.png

Using Duplex Broker

The core idea of the example is using the duplex broker component from Eneter Messaging Framework. It provides functionality for sending notification events (publishing) as well as for subscribing to desired events.
When the broker receives a notification message it forwards it all subscribers which are interested in this type of notification.
The cross-platform aspect of the Eneter framework ensures messages between JavaScript and .NET are understood (e.g. it takes care about UTF16 vs UTF8 or little-endian vs big-endian).

.NET Service Application

The service application is a simple .NET console application that regularly checks the CPU usage. Then it uses the broker component to publish the value. The broker searches which clients are subscribed for this type of event and forwards them the message.

Also because JavaScript uses the JSON serializer the service uses the JSON serializer too. It also sets the duplex broker to use the JSON serializer.

The whole implementation is very simple:

using System;
using System.Diagnostics;
using System.Threading;
using Eneter.Messaging.DataProcessing.Serializing;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.WebSocketMessagingSystem;
using Eneter.Messaging.Nodes.Broker;

namespace CpuUsageService
{
    // Message that will be notified.
    public class CpuUpdateMessage
    {
        public float Usage { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // JavaScript uses JSON serializer so set using JSON.
            ISerializer aSerializer = new DataContractJsonStringSerializer();

            // Create broker.
            IDuplexBrokerFactory aBrokerFactory = new DuplexBrokerFactory(aSerializer);
            IDuplexBroker aBroker = aBrokerFactory.CreateBroker();

            // Communicate using WebSockets.
            IMessagingSystemFactory aMessaging = new WebSocketMessagingSystemFactory();
            IDuplexInputChannel anInputChannel = 
               aMessaging.CreateDuplexInputChannel("ws://127.0.0.1:8843/CpuUsage/");

            anInputChannel.ResponseReceiverConnected += (x, y) =>
            {
                Console.WriteLine("Connected client: " + y.ResponseReceiverId);
            };
            anInputChannel.ResponseReceiverDisconnected += (x, y) =>
            {
                Console.WriteLine("Disconnected client: " + y.ResponseReceiverId);
            };

            // Attach input channel and start listeing.
            aBroker.AttachDuplexInputChannel(anInputChannel);

            // Start working thread monitoring the CPU usage.
            bool aStopWorkingThreadFlag = false;
            Thread aWorkingThread = new Thread(() =>
                {
                    PerformanceCounter aCpuCounter =
                      new PerformanceCounter("Processor", "% Processor Time", "_Total");

                    while (!aStopWorkingThreadFlag)
                    {
                        CpuUpdateMessage aMessage = new CpuUpdateMessage();
                        aMessage.Usage = aCpuCounter.NextValue();

                        //Console.WriteLine(aMessage.Usage);

                        // Serialize the message.
                        object aSerializedMessage =
                           aSerializer.Serialize<CpuUpdateMessage>(aMessage);

                        // Notify subscribers via the broker.
                        // Note: The broker will forward the message to subscribed clients.
                        aBroker.SendMessage("MyCpuUpdate", aSerializedMessage);

                        Thread.Sleep(500);
                    }
                });
            aWorkingThread.Start();

            Console.WriteLine("CpuUsageService is running press ENTER to stop.");
            Console.ReadLine();

            // Wait until the working thread stops.
            aStopWorkingThreadFlag = true;
            aWorkingThread.Join(3000);

            // Detach the input channel and stop listening.
            aBroker.DetachDuplexInputChannel();
        }
    }
}

JavaScript Client

The JavaScript client is a simple HTML 5 web-page using the duplex broker client component for subscribing to CPU usage notifications. When the notification message is received it updates the chart displaying values. The chart is moving as new notification values are received.

The whole implementation is very simple:

<!DOCTYPE html>
<html>
    <head>
        <title>CPU Usage Client</title>
        
        <script src="Chart.js"></script>
        <script src="eneter-messaging-6.0.1.js"></script>

        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body onunload="closeConnection();">
        <div>
            <button type="button" onclick="openConnection();">1. Open Connection</button>
        </div>
        <div>
            <button type="button" onclick="subscribe();">2. Subscribe</button>
            <button type="button" onclick="unsubscribe();">3. Unsubscribe</button>
        </div>
        <div>
            <button type="button" onclick="closeConnection();">4. Close Connection</button>
        </div>
        <div>
            <canvas id="canvas" height="300" width="300"></canvas>
        </div>
        
        <script>
            // Initialize chart.
            var myChartConfig = {
                        animation : false,
                        scaleOverlay : true,
                        scaleOverride : true,
                    scaleSteps : 10,
                        scaleStepWidth : 10,
                        scaleStartValue : 0
            };
            var myLineChartData = {
            labels : ["", "", "", "", "", "", "", "", "", ""],
            datasets : [
                {
                    fillColor : "rgba(220,220,220,0.5)",
                    strokeColor : "rgba(220,220,220,1)",
                    pointColor : "rgba(220,220,220,1)",
                    pointStrokeColor : "#fff",
                    data : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
                }
            ]
            
        };
            var myChart = new Chart(document.getElementById("canvas").getContext("2d"));
            
            // Create the duplex output channel.
            var myOutputChannel =
              new WebSocketDuplexOutputChannel("ws://127.0.0.1:8843/CpuUsage/", null);

            // Create BrokerClient
            var myBrokerClient = new DuplexBrokerClient();
            
            // Subscribe to notifications.
            myBrokerClient.onBrokerMessageReceived = onBrokerMessageReceived;
            
            function openConnection() {
                // Attach output channel and be able to send messages and receive responses.
                myBrokerClient.attachDuplexOutputChannel(myOutputChannel);
            };

            function closeConnection() {
                // Detach output channel and stop listening to responses.
                myBrokerClient.detachDuplexOutputChannel();
            };

            function subscribe() {
                myBrokerClient.subscribe("MyCpuUpdate");
            };

            function unsubscribe() {
                myBrokerClient.unsubscribe("MyCpuUpdate");
            };
            
            function onBrokerMessageReceived(brokerMessageReceivedEventArgs) {
                // If the notified message is the CPU status update.
                if (brokerMessageReceivedEventArgs.MessageTypeId === "MyCpuUpdate")
                {
                    // Deserialize notified message content.
                    var aValue = JSON.parse(brokerMessageReceivedEventArgs.Message);
                    
                    // Update data and draw the chart.
                    myLineChartData.datasets[0].data.shift();
                    myLineChartData.datasets[0].data.push(aValue.Usage);
                    myChart.Line(myLineChartData, myChartConfig);
                }
            };
        </script>
    </body>
</html>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ondrej_Uzovic
Architect
Slovakia Slovakia
My programming path started in 1987 when I got my first computer Sharp MZ-800.
It came with 8 bit CPU Z80, 64Kb RAM and the tape recorder. It was a great machine. I think I still have it somewhere.
I was fascinated and I started to write first programs. Eventually I became developer and software architect. I like innovations and clean nice solutions.

Comments and Discussions

 
QuestionHow to config IIS PinmemberMekki Ahmedi7-May-14 9:36 
AnswerRe: How to config IIS PinmemberMekki Ahmedi7-May-14 10:07 
GeneralRe: How to config IIS PinpremiumOndrej_Uzovic7-May-14 10:43 
GeneralVery nice PinmemberMekki Ahmedi7-May-14 8:32 
GeneralRe: Very nice PinpremiumOndrej_Uzovic7-May-14 9:27 
GeneralRe: Very nice PinmemberMekki Ahmedi7-May-14 10:07 
GeneralRe: Very nice PinpremiumOndrej_Uzovic7-May-14 10:44 
QuestionUse HTML5 push notifications on smartphones PinmemberBeetRoot1236-May-14 13:32 
AnswerRe: Use HTML5 push notifications on smartphones PinpremiumOndrej_Uzovic7-May-14 9:06 
QuestionI've come across your Eneter stuff before PinmvpSacha Barber5-May-14 21:54 
AnswerRe: I've come across your Eneter stuff before PinpremiumOndrej_Uzovic6-May-14 9:02 
QuestionGreat article so far but can you instruct to deploy into IIS/Internet? Pinmemberappxdev5-May-14 21:43 
AnswerRe: Great article so far but can you instruct to deploy into IIS/Internet? PinpremiumOndrej_Uzovic6-May-14 9:00 
Generalarticle is good Pinmemberpraveen_075-May-14 18:39 
SuggestionRegarding article section type PinmvpRanjan.D5-May-14 10:36 
GeneralRe: Regarding article section type PinpremiumOndrej_Uzovic5-May-14 10:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140905.1 | Last Updated 5 May 2014
Article Copyright 2014 by Ondrej_Uzovic
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid