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 <a href="http://www.eneter.net/ProductInfo.htm">Eneter.Messaging.Framework</a>
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.
- Download Eneter for Javascript from http://www.eneter.net/ProductDownload.htm.
- Copy Eneter for Javascript into CpuUsageClient directory.
- Open index.html file in an editor and ensure it uses the same version of eneter-messaging as you downloaded.
- 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.
Using Duplex Broker
The main 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
{
public class CpuUpdateMessage
{
public float Usage { get; set; }
}
class Program
{
static void Main(string[] args)
{
ISerializer aSerializer = new DataContractJsonStringSerializer();
IDuplexBrokerFactory aBrokerFactory = new DuplexBrokerFactory();
IDuplexBroker aBroker = aBrokerFactory.CreateBroker();
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);
};
aBroker.AttachDuplexInputChannel(anInputChannel);
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();
object aSerializedMessage =
aSerializer.Serialize<CpuUpdateMessage>(aMessage);
aBroker.SendMessage("MyCpuUpdate", aSerializedMessage);
Thread.Sleep(500);
}
});
aWorkingThread.Start();
Console.WriteLine("CpuUsageService is running press ENTER to stop.");
Console.ReadLine();
aStopWorkingThreadFlag = true;
aWorkingThread.Join(3000);
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>
<!- ENSURE HERE IS THE SAME ENETER VERSION AS YOU DOWNLOADED -->
<script src="eneter-messaging-6.5.0.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>
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"));
var myOutputChannel =
new WebSocketDuplexOutputChannel("ws://127.0.0.1:8843/CpuUsage/", null);
var myBrokerClient = new DuplexBrokerClient();
myBrokerClient.onBrokerMessageReceived = onBrokerMessageReceived;
function openConnection() {
myBrokerClient.attachDuplexOutputChannel(myOutputChannel);
};
function closeConnection() {
myBrokerClient.detachDuplexOutputChannel();
};
function subscribe() {
myBrokerClient.subscribe("MyCpuUpdate");
};
function unsubscribe() {
myBrokerClient.unsubscribe("MyCpuUpdate");
};
function onBrokerMessageReceived(brokerMessageReceivedEventArgs) {
if (brokerMessageReceivedEventArgs.MessageTypeId === "MyCpuUpdate")
{
var aValue = JSON.parse(brokerMessageReceivedEventArgs.Message);
myLineChartData.datasets[0].data.shift();
myLineChartData.datasets[0].data.push(aValue.Usage);
myChart.Line(myLineChartData, myChartConfig);
}
};
</script>
</body>
</html><font color="#111111" face="Segoe UI, Arial, sans-serif"><span style="font-size: 14px; white-space: normal;">
</span></font>