XAML Playground
about XAML and other Amenities

Improve PollingDuplex reliability with Silverlight 3.0

2009-04-07T23:43:23+01:00 by Andrea Boschin

The need to consume a continuous flow of data from a RIA application has two tipical solution. The first one involve the use of a Socket channel and probably is the most realiable when there is full acces to the ports  exposed by a server to the network. But this is rarely an available solution. Firewall, proxies and other kind of network apparates often restrict the access to a very tiny set of ports, possibly only to the http port 80. In this case the last solution available is to continuous poll the server and pulling data at every timeout.

timetableThis tecnique is slightly inefficient and prone to overload the server. If the need is to have very fast updates you have to rely on very short timeout but this may cause the server to fail under a great number of clients. On the other side having a long timeout may lost precision on the updates and give bad informations to users.

Silverlight 2.0 introduced a new mode to consume WCF services that allow to have the better of the server polling, using the only available http port, without short timeouts. With long timeouts we may also have updates very quickly thanks to a smart polling tecnique. Polling a server usually cause the client to be connected to the server only for few milliseconds and between connections there is a long disconnected period (the timeout). With Silverlight 2.0 PollingDuplex, channels can be connected during the whole timeout period and disconnect only for the short time needed to refresh the connection or notify the client of available updates. To do this "magic" the PollingDuplex simply open a connection to the server and wait for this connection to expire for a given period of time. If something happen on the server during this waiting the connection will be closed by the server itself and the client receive the notification with the related data.

Since its implementation many months ago this tecnique has been covered by many articles on the Internet so we do not need to add some other words to them. Here we need instead to analyze the changes that Silverlight 3.0 have introduced in this implementation that grant the developer a more reliable and simple usage of the PollingDuplex channels. To explore this new model I introduce a simple but effective application that monitors bus traffic.

Setup PollingDuplexHttpBinding

With Silverlight 2.0 setting up a duplex channel was a task hard and prone to errors. Due to the missing of an auto generated proxy the creation of a duplex connection and the control of its lifetime involve the direct usage of WCF channels and the management of at least a thread to monitor the polling channel. A detailed article explaining this tecnique may be found .

The main activity for the Silverlight team on this feature was to simplify the task of establishing the connection. With Silverlight 3.0 Visual Studio now support the generation of proxy class directly from the IDE in a similar way what we do with normal WCF services.

After the creation of the proxy - where it is possible to set properties like the type to be used for collections and dictionaries - the IDE generates a client class that can be simply used to establish the connection and receive updates. Here is a snippet of code, from the downloadable source, that show how to complete this task:

   1: /// <summary>
   2: /// Starts this instance.
   3: /// </summary>
   4: public static void Start()
   5: {
   6:     CustomBinding binding = new CustomBinding(
   7:         new PollingDuplexBindingElement(),
   8:         new BinaryMessageEncodingBindingElement(),
   9:         new HttpTransportBindingElement());
  10:  
  11:     TimeServiceClient client = new TimeServiceClient(binding, GetEndPoint());
  12:     
  13:     client.UpdateReceived += new EventHandler<UpdateReceivedEventArgs>(client_UpdateReceived);
  14:     client.RegisterAsync();
  15: }

In this few lines of code the TimeServiceClient is created. This client has to be setup with a binding compatible with the binding exposed by the server. In this case we need a custom binding using the new binary XML through the BinaryMessageEncodingBindingElement. The other element used establish a PollingDuplex channel over an http transport.

The other lines of code attach an Update event (exposed by the CallbackContract interface) and then calls the Register method (exposed by the ServiceContract) to start the polling. When this method completes - and we have an event available to check about his completion - the channel is up and running. Every time an update is available the UpdateReceived event will be raised and we may update the interface according to this data.

On the client the work is done. There is no need to have threads and all the received updates are always marshaled to the UI thread context so it is possible to update directly the User Interface.

In this sample we will simulate a timetable that show incoming races on a bus stop. When a bus is arriving to the stop the server will update the connected clients that will shows the times on the Silverlight scene. In this scenario we need to have very quicly updates and to minimize the traffic and the server work.

Creating a WCF Polling Server

The server side of the polling channel is slightly more complicated. This is not due to complexity of the PollingDuplex channel, but due to the needs to maintain trace of the registered clients and to notify them every time an update is available.

A polling duplex channel is made of two contracts instead of the usual one of normal WCF services. The first contract represent the normal ServiceContract that expose the ServiceOperations available to be called. On the other way we need to have a CallbackContract that say how a server can call on a client when an update is available and needs to notify it.

When a client connect to the service, using the Register method, the service itself will ask the OperationContext about the CallbackContract available over the client. An instance of the contract, returned by the GetCallbackChannel<T>() method will be retained by the service and used whenever it need to notify clients. Mantaining this instances needs to manage a shared collection of items and syncronize access to the elements using a lock statement. This is required because when a service instance has been created it is shared by all the calls that the service handles. So in a multi threaded environment like the context of a running webserver we have to keep in mind that the concurrency on the client callbacks contracts can affect the performances of out system.

In the sample attached to this article this responsability is of the TimeRunner class that handles the clinet collection and manage locks:

   1: /// <summary>
   2: /// Registers the specified client.
   3: /// </summary>
   4: /// <param name="client">The client.</param>
   5: public static void Register(ITimeServiceClient client)
   6: {
   7:     lock (lockObj)
   8:     {
   9:         TimeClient timeClient = new TimeClient(client);
  10:         timeClient.Fault += new EventHandler(timeClient_Fault);
  11:         TimeRunner.Clients.Add(timeClient);
  12:  
  13:         // ... omissis ...
  14:     }
  15: }

Another responsibility we have on the server side is the management of the client Fault states. A fault is the condition we may encounter when trying to send and update to a callback we get an exception because the client has been closed. There is no way to be notified about client disconnection so the only way to get rid of this problem is catching exceptions during an update. For each client connected to the service it will create an instance of a TimeClient class. This class checks the fault states when a client is updating and raise an event that signal to the TimeRunner the needs of remove the TimeClient instance from the collection:

   1: /// <summary>
   2: /// Handles the Fault event of the timeClient control.
   3: /// </summary>
   4: /// <param name="sender">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
   6: private static void timeClient_Fault(object sender, EventArgs e)
   7: {
   8:     lock (lockObj)
   9:     {
  10:         TimeClient timeClient = (TimeClient)sender;
  11:         TimeRunner.Clients.Remove(timeClient);
  12:         timeClient.Dispose();
  13:     }
  14: }

Let doing something...

Now that the service communication layer has been prepared to handle multiple incoming requests and updates we need to proceed start doing something in the service. While a normal WCF service simply handle calls from the web to do its work syncronous with the client, a Duplex service has to act as a worker thread that get notifications about the monitored resource and then contact the clients to send updates. The worker thread can wait for a database table to be updated, or can wait for other incoming event. In my sample I use a FileSystemWatcher to monitor changes to an xml file. The timetable.xml file contains sample data about races passing in a bus stop. I imagined that a windows service is collecting informations about the bus running ina town and when it have updates simply write to a xml file. This writing is catched by the FileSystemWatcher and notify the WCF duplex service thread. The notification received by the service cause the timetable to be loaded and a diffgram is send to the connected clients.

   1: /// <summary>
   2: /// Handles the Changed event of the Watcher control.
   3: /// </summary>
   4: /// <param name="sender">The source of the event.</param>
   5: /// <param name="e">The <see cref="System.IO.FileSystemEventArgs"/> instance containing the event data.</param>
   6: private static void Watcher_Changed(object sender, FileSystemEventArgs e)
   7: {
   8:     RacesTable table = LoadRaces();
   9:  
  10:     RaceUpdate update = new RaceUpdate
  11:     {
  12:         AddedOrModified = (from upd in table.Races
  13:                            where !TimeRunner.CurrentTable.Races.Contains(upd)
  14:                            select upd).ToArray(),
  15:         Deleted = (from old in TimeRunner.CurrentTable.Races
  16:                    where !table.Races.Select(rc => rc.UniqueID).Contains(old.UniqueID)
  17:                    select old).ToArray()
  18:     };
  19:  
  20:     lock (lockObj)
  21:     {
  22:         for(int i=0; i<TimeRunner.Clients.Count; i++)
  23:         {
  24:             TimeClient client = TimeRunner.Clients[i];
  25:             if (!client.IsSending) client.Send(update);
  26:         }
  27:     }
  28:  
  29:     TimeRunner.CurrentTable = table;
  30: }

The diffgram is calculated using an image of the timetable in memory that contains the latest version of the file. The new file and the old image is compared using linq and the diffgram is created with Added, Modified and Deleted items. The client that receive this update simply apply this changes tho his own copy of the timetable. The only exception to this flow happen when a client connect . In this case it get the complete content of the timetable from the memory of the service.

Hosting service and serving policies

A duplex service may be hosted by Internet Information Service, by a windows service or by a simple console application. In this example I choose to use a console application to maintain the source code simple. While using the IIS as host allow to serve clientaccesspolicy.xml files in a simple way, using a windows process needs to implements some tricks to serve this file as we did if we have a webserver. To do this I've implemented an endpoint using the webHttpBinding and return the xml file when it is requested. For more detail on this tecnique please read this .

Now that the sample has been described you may run it by yourself. Firts of all you need to run the service application and then starts the web application containing the Silverlight xap.

Download: Elite.Silverlight3.Polling.zip (1,4 MB)
Categories:   Networking
Actions:   E-mail | del.icio.us | Permalink | Comments (17) | Comment RSSRSS comment feed

Comments (17) -

April 27. 2009 17:20

Please change "analize" to "analyze". I'm not sure I even want to know what it means to "analize" something (someone?). Smile

Henrik

April 27. 2009 17:24

argh... you are right! I will change immediately Smile

Andrea Boschin

April 27. 2009 18:45

Thanks for the great article.  My company is developing a large inventory application in Silverlight, and they would like realtime update.  Our debate is Sockets or Duplex polling.  As the article stated polling can be inefficient and prone to server overload.  Our main concern is that it be robust enough to handle a large number of connected clients, which has us leaning toward Sockets.  We are not necessarly concerned about having extremely fast updates, meaning a couple seconds wouldn't be a problem.  Most examples I have seen using Duplex polling are simple chat applications.  Our application is much more data intensive and would require users viewing lists of inventory to see realtime inventory.  

Does the new Duplex Polling(smart polling) have the same issues with server overload, or is it less of a concern now that it uses smart polling?  

Any advice on whether Duplex polling would be an option for this type of app, or would Sockets be the only suitable solution?

Matt

April 27. 2009 20:29

Hi Matt and many thanks.
About your question I've to remember that the main difference between traditional polling and duplex polling is that in the first case you have at least a thread opened for each request and every thread do exacly all the works (e.g. queryng the database, scanning the filesystem, etc...). In the duplex polling you have only one thread doing the hard work and it notify all the clients. You have a difficult task in handle many client connected and I would want to see how the server will react to this load, but I think that you start with a better usage of the server resources. Your decision has to be taken after a needed test stage, but in my opinion duplex polling may be a good starting point.

Andrea Boschin

April 27. 2009 22:06

Andrea,

Thanks for the information, this difference between traditional and duplex polling is very good to know.  I agree testing will be needed to decide which is better for my situation, but considering some of the restrictions and complexities of Sockets and my limited experience with them, glad to hear Duplex is an option to consider.

Matt

Matt

June 7. 2009 16:02

Polling duplex is a technology based on the client polling on to the server. It is smart enough to answer instantly to events on server but cannot handle events occured between a disconnection and a reconnection from a client. While 5 milliseconds is a very short timeout you need to rely on a socket to push alle the events to the client.

Andrea Boschin

June 7. 2009 21:36

hello
      I want to know does SL 3.0 offer pure pushing technology (mean when ever server up it send data to connected client) , with a speed of 1 message at every 5 millsecond.

i belive polling duplex is like client periodly poll data for server , reather server send data to client when ever server update plz response ASAP
Regards

irfan

June 26. 2009 19:11

Great article.  And I appreciate you make your code available.  I've tried creating my own from scratch based on your example, but my proxy that is genreated by an "add service" from the IDE always uses ClientBase for the client base class, instead of DuplexClientBase.  Furthermore, it doesn't even generate the same methods - the callback methods, such as your UpdateRecieved and corresponding event args are completely absent.

How did you generate your proxy?  Based on the solution (and how it sits under Service References), it would seem it was done by the IDE "Add Reference", instead of the command line tool.  

Matt

June 26. 2009 22:18

Hi Matt, Thank you for your appraisal.
About your problem I thinkk you miss some configuration on the ServiceContract and CallbackContract. You have to be aware of the AsyncPattern = true I specify on the ITimeServiceClient contract and of the Begin/End pattern I used in the same contract. If you are unable to solve your problem please feel free to contact me by mail and send a small project to me.

Andrea Boschin

July 28. 2009 07:53

Hrmm that was weird, my comment got eaten. Anyway I wanted to say that it's nice to know that someone else also mentioned this as I had trouble finding the same info elsewhere. This was the first place that told me the answer. Thanks.

Steven W. Scott

July 28. 2009 07:58

Hi Steven, the comments are moderated due to heavy spamming during last days. Thanks for the post.

Andrea Boschin

August 1. 2009 00:09

Hello
i have generated new proxy class for the same service,
but Poxy class not showing the callback methods,
it is not showing UpdateReceived method.
Regards,
krishna

krishna

September 13. 2009 13:02

Thanks for the great article.

I have a doubt.
How can be notified from client to server that some data has been changed?

memphis

September 13. 2009 13:18

you can implement a normal method of the wcf service on a separate contract.

Andrea Boschin

September 22. 2009 23:12


The title of this article is a little confusingSmile. I hoped to find here an answer regarding the "reliability" of this binding in wcf sense, that is: Transport Reliability, Message Reliability and Ordered Messages.

Ernest Morariu

November 28. 2009 05:08

Andrea,
I'm trying to understand your code. I guess I don't have enough knowledge about WCF. Could you provide a reference for how you set up the service host?

Thx,
-j

joniba

November 28. 2009 13:47

Hi joniba, the better is you download the code attached to this article and you will found a working sample where there is both the Service (with its host) and the Client.

Andrea Boschin

Pingbacks and trackbacks (1)+