(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

The duplex story: looking at duplex communication in Silverlight (Part 1)

(10 votes)
Gill Cleeren
>
Gill Cleeren
Joined Apr 02, 2010
Articles:   63
Comments:   6
More Articles
12 comments   /   posted on Jul 05, 2010
Categories:   Data Access , General

This article is compatible with the latest version of Silverlight.

This article is Part 1 of the series The Duplex Story in Silverlight.

Silverlight offers us many choices to work with services to get data into our applications. Supported technologies include WCF, ASMX, REST, WCF RIA Services etc. Through the use of any of these, it’s quite easy to get data from the server to the client application and vice versa. They all have one thing in common: before the data is sent, the client has to perform a request to the server to do so. The communication is known to be client-initiated. But what if the server wants to initiate communication by sending some data to the client, without there being a request first? In this case, we need to use duplex communication, so that both sides of the communication channel can start sending data.

In this 3 part article, we’ll look at the options that Silverlight has on board to perform duplex communication. In this first part, we’ll start by looking at where this can be useful, followed by a first possible implementation, the HttpPollingDuplex. The source code for this article can be downloaded here.

The need for duplex communication

Before we start with the first possible implementation of duplex communication, let’s first take a look in which scenarios this can be useful.

Assume the following scenario (which will be the scenario for the demo later on as well).

You have been asked to build a Silverlight application that displays train delays as can be seen in the screenshot below. An external system drops an XML file in a specific folder whenever a train is delayed and drops another XML file when the train delay is to be removed. Your Silverlight application should be displaying up-to-date information about these train delays.

traindelays

A first attempt on how to solve this could be the following. We can write a WCF service that includes a method which returns these delays (internally, it would read out the contents of the folder and return them as a list of delays). In our Silverlight application, we can code a Timer that polls the service every 30 seconds. That would mean that each 30 seconds, the server gets a request from our application.

In rush hour traffic, we can assume that every 30 seconds, the service will return some new information, meaning that our requests are useful: we get some new information on train delays with each request. However, during the night or on a Sunday, not many trains are riding and therefore, not many delays are being generated. Probably, we are making a lot of useless requests to the service: with many requests, we’ll get no updates. The only thing we are doing here is needlessly creating load on the service by sending many requests which aren’t returning anything useful.

In the latter case, it would be much more beneficiary if the service itself could initiate the communication. In other words, when a delay is created or removed, the service would start sending updated information to the client. This is exactly where duplex communication comes in. With duplex communication, messages can be sent by the client as well as the server. The server does not need to wait for a request to come in before it can send a message to the client; it can do so whenever necessary.

Advantages of duplex communication

The advantages of communicating duplex are the following:

  • Scalability: if more than one client (in real world scenarios, this would of course be the case) is connecting to the service and they would all start polling the service needlessly, we are quite logically limiting the scalability of the service. Many requests won’t return anything useful. If we can make the service initiate the communication, the scalability will increase quite a lot. Since clients aren’t polling (and therefore creating load on the server), with the same hardware, we will be able to connect many more clients at the same time.
  • Speed of the response: if we are polling with a 30 second interval, we may have to wait up to 30 seconds to get new information. In a duplex scenario where the server can send a message immediately when this is required, clients get the new messages more quickly.

Types of duplex communication in Silverlight

Duplex communication has been supported in Silverlight since version 2; however, some changes and additions have been made in Silverlight 3 and 4. Version 4 now supports 3 different types of duplex communication:

  • HTTP Polling Duplex: this type was already available in Silverlight 2, but was changed somewhat in Silverlight 3 (actually it was made easier). We’ll look at this type in this article.
  • Sockets: sockets were already available in Silverlight 2; some minor changes were made in Silverlight 4. We’ll focus on sockets in the next article of this series
  • net.tcp binding: this entirely new binding, added in Silverlight 4, also supports duplex communication. net.tpc will be topic of the third article.

There is in fact a fourth way to do duplex communication and that’s the manual approach, as we explained earlier. In this type, we have to create the requests ourselves at certain intervals, that is, a polling mechanism. It’s hard to find an optimal solution here, since we need to decide on a poll time. Making this too low will result in faster updates but decrease the server’s scalability. Making it too high will result in the client not being updated frequently enough. Therefore, in most scenarios, the manual approach is not a good way to solve duplex communication problems.

Let’s now focus on polling duplex binding.

The HTTP Polling Duplex Binding in Silverlight

As already mentioned, normally a response is only sent by the server as a reaction on a request sent by the client. This is typical for HTTP communication. Duplex requires that the server can itself initiate communication, which is not supported by HTTP.

The HTTP polling duplex binding however allows us to do this bi-directional communication over HTTP. What happens behind the scenes is the following:

  • The Silverlight client initiates the communication by sending an initial request to the service.
  • After the client is registered with the service, it continuously starts polling the service for updates.
  • Whenever the service has new messages to send to the client, they are queued up until a new poll arrives from the client.

Wait, let’s take a step back. We just said that polling is not a good idea and this solution actually does polling? Indeed it does. However, it does polling with a twist: continuously, requests are created on the network layer to see if new messages are ready, resulting in less overhead. This way, we are able to get updates almost immediately (since the polling is done continuously) and still scale quite well. The HTTP Polling Duplex is therefore not real duplexing: it creates an illusion of duplex communication by polling so frequently that it looks as if the messages are pushed from the service to the client.

The client actually polls the service until the PollTimeout occurs. The PollTimeout is by default set to 60 seconds. Once it reaches this timeout, a check is done to see if the session is still OK and if it is, an empty message is sent. After that, the polling starts again.

A second timeout exists: the InactivityTimeout. This occurs after 10 minutes of no data being sent. This is equal to 10 PollTimeouts occurring without data being sent over.

Internals of the HTTP Polling Duplex

The binding

The HTTP Polling Duplex uses the HttpPollingDuplex binding, which inherits from the BasicHttpBinding. Internally, it uses HTTP for its transport, the Net Duplex protocol for the initial connection from the client to the service and the WS Make Connection protocol to allow delivering messages from the service to the client.

Since the binding uses HTTP, it does not require any extra ports to be open (which is the case with sockets and net.tcp as we’ll see in the next article), making the HTTP Polling Duplex a perfect fit for duplex communication over the internet.

To enable this binding, we need to reference an assembly, System.ServiceModel.PollingDuplex, both in the service project and the Silverlight client. This assembly is available in the %Program Files%\Microsoft SDKs\Silverlight\v4.0\Libraries\Server directory for the service and %Program Files%\Microsoft SDKs\Silverlight\v4.0\Libraries\Client for the Silverlight client.

In configuration (web.config), we need to add the following code:

<system.serviceModel>
  <extensions>
    <bindingExtensions>
      <add name="pollingDuplexHttpBinding" 
        type="System.ServiceModel.Configuration.PollingDuplexHttpBindingCollectionElement, 
        System.ServiceModel.PollingDuplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
    </bindingExtensions>
  </extensions>
  <bindings>
    <pollingDuplexHttpBinding>
    </pollingDuplexHttpBinding>
  </bindings>
  <services>
    <service name="DuplexTrains.Web.TrainDelayService" 
      behaviorConfiguration="DuplexTrains.Web.TrainDelayServiceBehavior">
      <endpoint address="" binding="pollingDuplexHttpBinding" 
        contract="DuplexTrains.Web.ITrainDelayService" />
      <endpoint address="mex" binding="mexHttpBinding" 
        contract="IMetadataExchange" />
      </service>
    </services>
</system.serviceModel>
 
This code registers the assembly, creates the new binding and assigns the endpoint to use this binding.
The service

The service itself is a WCF service and resembles a regular WCF service quite a lot. There are however some particularities compared to a standard WCF service:

  • It defines, next to the ServiceContract, a CallbackContract. This type will perform the callback to the client from the service instance.
  • The operations are defined with the IsOneWay attribute set to True: this way, there will be no waiting for the response of the service call.
  • GetCallbackChannel<T>: this is used in the service instance upon registering the client with the service. The service calls the GetCallbackChannel<T> on the OperationContext to get an instance of the callback contract. It should then store this client reference in a list so that when an update needs to be sent out, it can loop over that list and send a message to each of the connected clients.

Below is the service contract for our sample.

[ServiceContract(Namespace = "Silverlight", CallbackContract = typeof(ITrainDelayServiceClient))]
public interface ITrainDelayService
{
  [OperationContract(IsOneWay = true)]
  void Connect(string id);
}
 
[ServiceContract]
public interface ITrainDelayServiceClient
{
  [OperationContract(IsOneWay = true)]
  void SendTrainDelay(TrainDelay delayInfo);
}

As can be seen, the ServiceContract – ITrainDelayService - also has a CallbackContract defined. ITrainDelayService defines just one method, Connect(), which is used to allow Silverlight clients to connect and register with the service. This Connect() method has the IsOneWay attribute applied, which is a sign for the client code it does not have to wait for a response from the service. The CallbackContract – ITrainDelayServiceClient – defines the SendTrainDelay() method, which is the method that will be invoked by the service on the client.

The implementation code for the Connect method is shown below:

public class TrainDelayService : ITrainDelayService
{
  public void Connect(string id)
  {
    ITrainDelayServiceClient client = OperationContext.Current.GetCallbackChannel<ITrainDelayServiceClient>();
    TrainServiceRunner.Register(client);
  }
}

In this Connect() method, we are getting an instance of the CallbackContract using the GetCallbackChannel() on the OperationContext. All clients that are connecting to the service are connecting to the same service instance. This one service instance will get the updates in (from when a file of a train delay was created or deleted, service calls, database triggers etc) and will also be the service instance that keeps a list of connected clients. This is shown in the code below (the Register() method used above):

public static void Register(ITrainDelayServiceClient client)
{
  lock (myLock)
  {
    clients.Add(client);
  }
}

When a train delay file is added or removed, the service code should run over the list and invoke the SendTrainDelay() method on each connected client.

//when a file is added, loop over the connected clients 
lock (myLock)
{
  foreach (var client in clients)
  {
    client.SendTrainDelay(trainDelay);
  }
}
Clients

When we want our Silverlight application to communicate with the service, we start by adding a service reference. Visual Studio will create a proxy class but no configuration code is created. Therefore, some more code needs to be added manually: we need to create a CustomBinding instance, as shown in the following code:

EndpointAddress address = new EndpointAddress("http://localhost:2884/TrainDelayService.svc");
 
CustomBinding binding = new CustomBinding(
  new PollingDuplexBindingElement(),
  new BinaryMessageEncodingBindingElement(),
  new HttpTransportBindingElement());

The client can subsequently register itself with the service and from then on, it will be waiting for incoming messages from the service. These callbacks execute on the UI thread, meaning we do not need to use the Dispatcher and can directly access UI elements. The code below shows that we invoke the Connect() method asynchronously and wait for callback on the SendTrainDelay() using the callback.

TrainDelayService.TrainDelayServiceClient client = 
    new TrainDelayService.TrainDelayServiceClient(binding, address);
client.SendTrainDelayReceived += 
    new EventHandler<TrainDelayService.SendTrainDelayReceivedEventArgs>(client_SendTrainDelayReceived);
client.ConnectAsync(Guid.NewGuid().ToString());

Conclusion

In this first part of the series, we saw there are quite a lot of scenarios where we can benefit from duplex communication. The HttpPollingDuplex binding is a first of three ways to allow duplex from Silverlight. This type is a perfect fit for internet scenarios as it requires no extra ports to be opened. In the next part, we’ll look at sockets and their benefits.


Subscribe

Comments

  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 (Part 1)


    posted by Thanigainathan on Jul 05, 2010 21:07

    Very nice article.Thanks for introducing the duplex binding.

  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 (Part 1)


    posted by George on Jul 06, 2010 18:07
    Thanks for a great article. I've struggled for a while trying to understand duplex communication. I look forward to the others.
  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 (Part 1)


    posted by Aaron on Jul 07, 2010 04:44
    Thanks for the write up, nice work!
  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 (Part 1)


    posted by Andres on Aug 27, 2010 21:40
    Good work !
  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 (Part 1)


    posted by goldy on Aug 30, 2010 14:38

    Hi

    Great Post. Made lot of things clear. I just want to scale it further. In your project all the connected clients are getting the same notifications. Let us assume that as a client if i have subscribe fro only few trains notifications. then i should be notified for only those trains and not all the trains. can you pls guide me where should be this filters applied.

    Thanks

  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 (Part 1)


    posted by Tony on Sep 08, 2010 07:24
    Thanks for your post on duplex communication.  I was still confused reading your post then viewed the Silverlight TV post on Duplex Communication with WCF in Silverlight 4.  After that, your post became very clear.  Now on to part II and III.
  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 (Part 1)


    posted by Linh on Nov 12, 2010 12:48

    Nice tutorial, but when i open another multi-browser, it very slow or hang-on. how to solve this ?

  • -_-

    RE: The duplex story: looking at duplex communication in Silverlight 4 (Part 1)


    posted by David Sackstein on Dec 27, 2010 12:51

    I have a question about implementing asynchronous notification server->client using the polling duplex WCF channel in Silverlight 4.

     From what I have read, I need to do the following:

    1. Mark the callback contract methods that I want to call asynchronously with IsOneWay=true
    2. Make sure the ConcurrencyMode of the service is not set to Single.

     I am currently using InstanceContextMode=Single, but I find that even if I meet 1 and 2 above and even if I set the IndexContextMode to PerCall, the  "async" methods still block.

     What do I mean by block?

    I do not mean that they block on the wire because I am flooding the client. This indeed can be expected to block even a one way call.

    No, what I mean is that even if I make a single call to the async method, and put a Sleep (13645) in the client's event handler that handlers the call, then the server invocation returns after about 13800 msec. This is clearly no coincidence and tells me that the server is blocking until the client completes the call.

     Now, of course, I can overcome this by spawning an invocation of my call in a thread from the ThreadPool, but this is not really good enough.

    Using this method, I am likely to be flooding the server with threads that might all be waiting for a client.

    I can solve this again by configuring a small timeout on those outgoing calls and limiting the number of threads in the thread pool.

    But shouldn’t all of that been handled by the duplex channel?

     I would appreciate your insight …

  • -_-

    RE: The duplex story and why it should be easy instead of being difficult


    posted by fjdklfja;ghf on Jan 29, 2011 21:45

    This article is made to be difficult to follow and finally get rid of it and take the online presentation or to download the source code and followint it without reading the article.

    It's not difficult to understand why Flash still rullz :)

  • -_-

    Inactivity Timeout problem


    posted by HelpME on Feb 07, 2011 06:27
    After ten minutes from sending messages to the client, and since the client is not responding, the inactivitytimeout will fire up and the service will stop responding because it may think that the client (is inactive) since it only receives messages but sends nothing back. How do we overcome this problem? I have tried to set the value for this parameter to TimeSpan.max but nothing happened.
  • frinkfree

    Re: The duplex story: looking at duplex communication in Silverlight (Part 1)


    posted by frinkfree on Aug 08, 2011 16:56
    I recently ran into a problem with duplex channel timeout while printing in Silverlight. Since communication and printing seem to be happening on the highly coveted UI thread, the communication channel is starved while printing. Any suggestions on how to avoid channel timeout while printing? thx
  • Mas3oude

    Re: The duplex story: looking at duplex communication in Silverlight (Part 1)


    posted by Mas3oude on Jun 29, 2013 12:11

    how to unregister  the client from the service after closing the browser ??

    i cant do this

Add Comment

Login to comment:
  *      *       

From this series