Flex applications often need a way to be notified about changes or events taking place on the server-side. For instance, financial applications need to have a way to stream stock quote data to the rich clients. The same is true for data-driven applications - as data changes on the server, clients may need to be notified.
Solution
The proposed solution describes how to use the RTMP protocol to push data from a .NET application to the connected Flex clients using the NetConnection API.
Detailed explanation
Introduction
RTMP (Real-Time Messaging Protocol) is a binary
protocol supported by Flash Player which enables fast, efficient,
bidirectional communication between Flex/Flash clients and
server-side applications. The protocol supports data messaging for
various message exchange paradigms (client-to-client(s),
client-to-server, server-to-client(s)) as well as media (video and
audio) streaming and recording. WebORB for .NET supports the RTMP
protocol and provides facilities to enable data message exchanges
mentioned above as well as video streaming and recording. This
articles describes the setup, configuration and APIs for
implementing a data push from the .NET code to all connected
clients.
To get started make sure you have the following
software installed:
Flash Builder version 4
WebORB for .NET version 3.6.0.3 or later
Microsoft Visual Studio 2008 or later
Microsoft .NET framework v. 2.0 or later
Project Description
To demonstrate server-to-client data push over
RTMP, the article will use a Flex application which displays a
chart of the server's CPU allocation. The CPU readings will be read
by .NET code and delivered to the client using WebORB's Messaging
(RTMP) infrastructure. The diagram below illustrates the
process:
Project development will consist of two parts:
Flex client code connecting to the server and subscribing to
receive server-side updates with the CPU readings. The code also
includes a chart to visualize the received data.
The server-side 'Application handler' which plugs into
WebORB, polls CPU and delivers data to the client.
Developing .NET Code
WebORB Messaging infrastructure has an
abstraction of 'application handler'. An application handler
represents a messaging application also referred to as application
scope. When a client connects to the server, it must specify the
application by name. Application scope shares all the context
managed within the application, provides access to all the client
connections and shared objects. The code below is the application
handler for the CPU Monitoring example reviewed in this
article:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Timers;
using Weborb.Messaging.Api.Service;
using Weborb.Messaging.Api;
using Weborb.Messaging.Server.Adapter;
namespace CPUMonitor
{
public class CPUMonitoringAppHandler : ApplicationAdapter
{
private Timer cpuReadingTimer;
private PerformanceCounter cpuCounter;
// invoked when WebORB for .NET starts up
public override bool appStart( IScope app )
{
bool appStarted = base.appStart( app );
// if application could not start for any reason, do not
proceed further
if( !appStarted )
return appStarted;
// initialize performance counter
cpuCounter = new PerformanceCounter();
cpuCounter.CategoryName = "Processor";
cpuCounter.CounterName = "% Processor Time";
cpuCounter.InstanceName = "_Total";
// start thread to get CPU readings
cpuReadingTimer = new Timer( 1000 );
cpuReadingTimer.Elapsed += new ElapsedEventHandler(
cpuReadingTimer_Elapsed );
cpuReadingTimer.Start();
return appStarted;
}
void cpuReadingTimer_Elapsed( object sender, ElapsedEventArgs
e)
{
// ignore timer event, if there are no connected clients to
the scope
if( scope.getClients().Count == 0 )
return;
// get the CPU reading
float cpuUtilization = cpuCounter.NextValue();
// create an array of values to deliver to the client.
// there is only one value, but the API requires it to be an
array
object[] args = new object[] { cpuUtilization };
// get an enumeration of connections to this application
IEnumerator<IConnection> connections =
scope.getConnections();
while( connections.MoveNext() )
{
IConnection connection = connections.Current;
// invoke client-side function to deliver CPU reading
if( connection is IServiceCapableConnection )
((IServiceCapableConnection) connection).invoke(
"processCPUReading", args );
}
}
}
}
The CPUMonitoringAppHandler class is the
application handler for the messaging application. The class must
extend the ApplicationAdapter class. (The base class is in the
Weborb.Messaging.Server.Adapter namespace).
CPUMonitoringAppHandler declares and creates a timer. The timer
wakes up every second and checks if the application has any
connected clients. If there is at least one client, the timer
event gets the latest CPU reading using PerformanceMonitor API
and subsequently delivers the reading value to all connected
clients.
Once the assembly with the application handler
is deployed, it must be registered as a messaging application.
The instructions below describe the process:
Locate the /Applications folder in the root of your WebORB
installation. If you use WebORB version 3 for .NET, the folder
is located in /inetpub/wwwroot/weborb30/. If you use WebORB
version 4 for .NET, the folder is under /Program
Files/WebORB/4.0/
Create CPUMonitoringApp subfolder under Applications/. The
name of the folder is going to be the name of the application.
This is the name Flex clients will use to connect to the
server/application.
Download
this
file and extract its contents into the CPUMonitoringApp
directory. Once you do that the directory should have
app.config file inside. For the verification purposes, open
app.config and make sure the name of the class in the
application-handler element matches the full type name of your
application handler.
You can use WebORB Management Console to verify if the
messaging application is properly deployed. if you use WebORB
version 3 select Management and then Messaging Server. The name
of the application (CPUMonitoringApp) should appear in the list
of application. With version 4 of WebORB, you should see the
name of the application on the main overview screen.
<?xml version="1.0"
encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
creationComplete="init()">
<fx:Declarations>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
[Bindable]
private var cpuValues:ArrayCollection = new ArrayCollection();
private var serverConnection:NetConnection;
private function init():void
{
serverConnection = new NetConnection();
serverConnection.addEventListener(NetStatusEvent.NET_STATUS,handleStatus
);
serverConnection.client = this;
serverConnection.connect(
"rtmp://localhost:2037/CPUMonitoringApp");
for( var i:int = 0; i < 100; i++ )
cpuValues.addItem( 0 );
}
private function handleStatus( evt:NetStatusEvent ):void
{
switch( evt.info.code )
{
case "NetConnection.Connect.Success":
break;
case "NetConnection.Connect.Failed":
Alert.show( "Unable to connect to WebORB", "Connection Error"
);
break;
}
}
public function processCPUReading( cpuUtilization:Number ):void
{
// create sliding chart effect
cpuValues.removeItemAt( 0 );
cpuValues.addItem( cpuUtilization );
}
]]>
</fx:Script>
<s:Panel left="5" right="5" top="5" bottom="5"
title="Server CPU Utilization">
<mx:LineChart id="cpuChart"
left="10" right="10" top="10" bottom="10"
dataProvider="{cpuValues}">
<mx:series>
<mx:LineSeries displayName="CPU(%)" yField=""/>
</mx:series>
</mx:LineChart>
</s:Panel>
</s:Application>
The client code uses the NetConnection API
to connect to the server and receive server-to-client
(DataPush) callbacks. The "serverConnection" variable is
declared on line 16 and initialized on lines 20-26. Notice
the URL of the messaging application on line 26. The
"CPUMonitoringApp" part of the URL refers to the messaging
application created earlier in the article. It is also
important to note the assignment on line 24. The "client"
property on NetConnection refers to the object which contains
the methods invoked from the server-side. In this example,
the same object (the Flex application itself) hosts the
method invoked on the server. The method is
"processCPUReading" (lines 45-50). The method receives an
argument value delivered by the server. The value is stored
in a bindable ArrayCollection - variable "cpuValues". The
chart (lines 55-61) uses cpuValues as the data provider. As
soon as the code updates the values in the array collection,
the chart is automatically updated.
When you run the example, you should
immediately see data in the chart. You can try running
multiple browsers with the example application. If the data
does not arrive, make sure the WebORB messaging server is
running - you can do that by opening the WebORB Management
Console.
A copy of this recipe is also available on the Midnight
Coders site at: