During a recent course with Stan James we discussed how Silverlight 3 could be used with duplex services to push data from the server to the clients; I wanted to produce a simple example of how to do this. Pushing data this way has a number of benefits:
- You reduce the load on the server; instead of multiple clients polling the server periodically, we send the data from the server to the clients as and when we want to.
- We can eliminate or reduce data lag in time sensitive applications – so as soon as we have the data available we can push it to Silverlight to react to. This can be very important for applications that need to show data changes as they happen, such as trading systems or perhaps live statistics from sports events such as Formula 1.
- All clients receive updates at the same time.
There is a nice sample application from Mix09 available here which creates a chat application as well as an example of a server push. However I felt a simpler example would have a benefit to many trying to get to grips with this, together with a bit more explanation. We will however use generic DuplexService class that is created in that project (it would make sense for a class like this to be available in the framework, or at least a template within Visual studio)
What our application will do
We want a simple example, and that is what we will get. The server will periodically push a “LiveData” message to any Silverlight client that has connected, and the client will display it. I am not concerned how the data gets to the server here, only how to send it out to the client once we have it.
How the project fits together
Creating the Sample
Creating the Project
First create a new Silverlight project; let’s call it DuplexExample – ensure you include a Asp.Net Web Application with the default name (DuplexExample.Web) . In the web site add a reference to the System.ServiceModel.PollingDuplex (make sure you get the correct one – the v3.0 one in the Server folder.)
And in the Silverlight project also add a reference to System.ServiceModel.PollingDuplex (but this time in the Client folder):
Download the Duplex sample from http://code.msdn.microsoft.com/silverlightws/Release/ProjectReleases.aspx?ReleaseId=2401, extract it and grab the DuplexService.cs file and drop it into your web site.
Creating the Service
Now we could add a Wcf service using Visual Studio templates, but that would actually create a lot of stuff we don’t need which we would just have to delete, so instead just add a text file but call it LiveDataService.svc . This will give us a blank file into which you can add the following:
<%@ ServiceHost
Language=”C#”
Debug=”true”
Factory=”DuplexExample.Web.LiveDataServiceFactory”
Service=”DuplexExample.Web.LiveDataService”
%>
The only difference here to the contents of a normal svc file is the fact that there is no CodeBehind value specified and we have explicitly specified a Factory class. (For more details on these options see here: http://msdn.microsoft.com/en-us/library/aa967286.aspx) Since we have specified a LiveDataService for our service and LiveDataServiceFactory class that will be used to instantiate the factory service, we will need to go and create these.
But before we can do that we need a DataContract class called LiveDataMessage – this is the simple class that our service will send to Silverlight.
[DataContract]
public class LiveDataMessage: DuplexMessage
{
[DataMember]
public int Value { get; set; }
[DataMember]
public string Description { get; set; }
}
Ok so now we can create our “LiveDataService” – add a class to your web site called LiveDataService.cs and add the following code. This is fairly simple – we are using a Timer to send a message to all clients every 5 seconds:
using System;
usingMicrosoft.Silverlight.Cdf.Samples.Duplex;
usingSystem.Threading;
namespace DuplexExample.Web
{
public class LiveDataService :DuplexService
{
Timer liveDataTimer;
public LiveDataService()
{
//Set up a an update every 5 seconds
this.liveDataTimer = newTimer(newTimerCallback(LiveDataUpdate),null, 0, 5000);
}
void LiveDataUpdate(objecto)
{
LiveDataMessage liveDataMessage = newLiveDataMessage()
{
Description = “Live Data at “+ DateTime.Now.ToLongTimeString(),
Value = newRandom().Next(0, 100)
};
PushToAllClients(liveDataMessage);
}
}
}
The DuplexService Class
You will notice that our LiveDataService inherits from the DuplexService we added to our project – this provides all the plumbing work for the duplex service:
Crucially this class is also marked with the following attribute, meaning our service can keep track of clients that have connected, because it stays in memory and is not recycled’:
Ok – so the DuplexService provides plenty of goodness for free, though there is one thing we need to alter in this file – you may have noticed already that it is not compiling. Down at the bottom you will see a list of KnownTypes. These related to the sample project you downloaded and not what we want. We only have one specific KnownType (apart from the Connect and Disconnect) called LiveDataMessage.
So you need to make the following change to the DuplexService.cs file (at the bottom) :
The LiveDataServiceFactory class
Finally we need to add the LiveDataServiceFactory class – which inherits from the DataServiceFactory class in the DuplexService.cs file (and in fact that’s all it will do)
namespace DuplexExample.Web { public class LiveDataServiceFactory : DuplexServiceFactory<LiveDataService> {} }
If you go and look at the DuplexServiceFactory we are inheriting from (again in the DuplexService.cs file) you will see that it provides the configuration for the service with a custom binding (this is an alternative to providing configuration for doing this)
The Silverlight Project
Make sure you can build your solution, then add a Service Reference from the Silverlight project to the LiveDataService you have created:
I created a very simple UI – just a button and a ListBox shown below:
<Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition Height="75"/> <RowDefinition Height="225"/> </Grid.RowDefinitions> <Button Content="Connect" Click="ButtonConnect_Click" x:Name="ButtonConnect" Margin="10"></Button> <ListBox Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible" x:Name="ListBox1"></ListBox> </Grid>

Here is all the code in MainPage.Xaml.cs. Take a look at it here then we’ll discuss it:
public partial class MainPage : UserControl { DuplexServiceClient receiver; ObservableCollection<string> liveDataMessages = new ObservableCollection<string>(); CustomBinding binding = new CustomBinding( new PollingDuplexBindingElement(), new BinaryMessageEncodingBindingElement(), new HttpTransportBindingElement() ); public MainPage() { InitializeComponent(); ListBox1.ItemsSource = liveDataMessages; //make sure the endpoint address is correct receiver = new DuplexServiceClient(binding, new EndpointAddress("http://localhost:6719/LiveDataService.svc")); receiver.SendToClientReceived += (sender, e) => { if (e.msg is LiveDataMessage) { LiveDataMessage msg = (LiveDataMessage)e.msg; liveDataMessages.Add(string.Format("{0}. Value = {1}", msg.Description, msg.Value)); } }; } bool connected = false; private void ButtonConnect_Click(object sender, RoutedEventArgs e) { if (connected) { Disconnect(); } else { Connect(); } } private void Connect() { ButtonConnect.Content = "Connecting..."; receiver.SendToServiceCompleted += (sender, e) => { ButtonConnect.Content = "Connected (click to disconnect)"; connected = true; }; receiver.SendToServiceAsync(new ConnectMessage()); } private void Disconnect() { ButtonConnect.Content = "Disconnecting..."; receiver.SendToServiceCompleted += (sender, e) => { ButtonConnect.Content = "Disconnected (click to connect)"; connected = false; }; receiver.SendToServiceAsync(new DisconnectMessage()); } }
At the top of this code, we declare 3 variables: the DuplexServiceClient,a CustomBinding (which matched the binding of the service we created on the server) and an ObservableCollection to store the messages we get from the server. We instantiate the DuplexServiceClient in the class constructor using the custom binding and and endpoint (make sure this is the correct address for your service) and wire up the SendToClientReceived event which is where we add the messages we get from the server to the observableCollection (which in turn shows them in the ListBox)
However we also need to provide a Connect method (which sends a ConnectMessage to the server) – this is to essentially to let the Duplex service on the server know we are here, and allow it to keep track us via a Session ID. You can see this in DuplexService.cs file as shown below (line 133):
The disconnect method does the reverse by sending a DisconnectMessage to the server which reacts like this (removing the client from it’s tracked session id’s)
Testing Your Application
Press F5 to run the application, then click the Connect button – you will see messages sent to Silverlight from the Server every 5 seconds. To make it more interesting, start a second browser instance and run the same application and connect that too. You will see both clients being updated at the exactly the same time.
Hope this is of use.
You can download the source code from here: http://cid-fb8b852ef1ab0b35.skydrive.live.com/self.aspx/SampleCode/DuplexExample.zip
Cheers
Ian
June 25, 2009 at 4:46 am
[...] more here [...]
June 26, 2009 at 8:47 am
[...] Duplex WCF Service para Silverlight – Como utilizar um serviço desta natureza nas aplicações Silverlight. [...]
August 5, 2009 at 10:05 pm
Hi !
The sample does not run. After the successful connection, nothing happens.
Like the MIX 09 sample – which is that bad, that it is even not able to build – I have never ever seen any version which runs.
Sorry for that.
br–mabra
August 6, 2009 at 4:15 pm
Hi,
The sample certainly builds and works for me and the class of delegates I had before me at Stan James
What error are you getting?
August 6, 2009 at 7:06 pm
Hi !
Thanks for your reply!
I said, the MSDN sample, does event not build! Your sample builds and runs without errors – so I got big hope
but I got no data in IE. Am I that new to SL and WCF, that I cannot anaylze the problem. In Firefox, a runtime error appears [control = new ActiveXObject('AgControl.AgControl');] although SL generally runs inside FF.
Any help would be great!
br–mabra
August 6, 2009 at 7:18 pm
It’s me again
I came to the idea – do something with the web – to run fiddler, and voila:I saw two failing requests, the first one for “/clientaccesspolicy.xl” and “/crossdoamin.xml”, with http:502. So I assume, for the final SL3, the sample misses something. Disabling windows firewall does not change this!
Help would be great!
br–mabra
August 6, 2009 at 7:45 pm
Hi Mambra,
It is possible you are running the silverlight client either cross domain/cross-zone or cross-scheme from the service. Take a look here: http://msdn.microsoft.com/en-us/library/cc189008(VS.95).aspx – you either need to put them in the same domain/zone/scheme or add a clientaccesspolicy to the root of the service app.
August 12, 2009 at 8:49 pm
Hi !
Thanks for your reply!!!!
I run the app in the developement environment and so far I understand the ussue right, this should/can not happen inside it!
br–mabra
August 6, 2009 at 4:07 pm
This example, as well as all others I have found have a 8192 buffer limitation. I added a simple Test method to the service that takes a string. When I call that method with a string size less than or equal to 8192, everything is fine.
However, if the string length is greater than 8192, a fault occurs stating “The server did not provide a meaningful reply”
I have tried to set the binding’s Max* variables without any success. Any Ideas how to get around this 8192 limitation with Duplex bindings?
August 6, 2009 at 4:16 pm
Interesting point – I would have thought wcf config – but you seem to have tried that. I will take a more detailed look and see what I can come up with.
August 24, 2009 at 5:12 pm
Thanks for the wonderful example. I am a newbie to SL and was looking for a good Server Push example. After down loading the application & fixing the policy xml issues, I am able to run my application as well as the MSDN app. I have a question. My data which the server is pushing comes from a data store and it has more than 500 records. I tried returning the List but the message is never received in the MainPage.xaml.cs on the event. When I send a single row, it is received (which is obviously not the solution) I tried to return a delimited string (again not a good ideas as string has its own size limit). I would like to know whether in SL3 can I send a List message from the server to client? If this is possible then can you provide with a example? And if this is not the case, I mean returning List is not possible then what is the way I can return all the rows to the client and further bind them to the DataGrid? Please comment.
August 27, 2009 at 12:15 am
Could you post SL3 client code which doesn’t use proxy generation/add Service Reference and uses the Channel Model instead?
(All existing samples, including MSDN ones no longer seem to work after migrating to SL3)
Thanks.
Alex Mikunov
August 28, 2009 at 5:56 pm
hi,
thanks for the concise sample.
have a question about the empty class:
public class DuplexMessage{}
why the empty class?
wouldn’t it make more sense to put something in there and then allow other classes to derive from it?
September 2, 2009 at 3:54 am
hi ian,
i downloaded your source code.
everything works with VS2008, SL3 July version, FW 3.5 SP1.
however, as a learning process, i DELETE the SERVICE REFERENCE and try to add it back in.
this is when i got error:
“An error (Details) occurred while attempting to find services at
http://localhost:6719/LiveDataService.svc ”
the LiveDataService.svc runs fine when i right-click and VIEW IN BROWSER.
nothing else changes in the original code except i DELETE the original SERVICE REFERENCE and try to add it back in.
this error occurs for all the projects that i downloaded that based on MIX 09 CHAT SAMPLE and all were built before SL3 July version.
just wondering if you know what might be the problem?
thanks….
September 2, 2009 at 3:40 pm
Ian,
This is great. Thanks for the insight; finally a good WCF example!
September 17, 2009 at 2:43 pm
bob,
I ran into the same issue. I’d bet that it is because you copied the contents of the LiveDataService.svc file right into the text file you added. The quotes didnt copy right for me, so just deleting the quotes and re-adding them resolved this issue and I can now add the service reference fine.
Hope this helps.
September 21, 2009 at 7:55 pm
I’m able to run the sample from visual studio but when i publish as an application to the local IIS 6 server no data comes down. (Connect / disconnect features work, just no data)
Is there a magic setting that i need to look at?
October 13, 2009 at 5:28 pm
excellent and simple! great way to simplifying the wcf duplex service for silverlight.
October 13, 2009 at 8:19 pm
Good work, Great samples and Great documentation, exactly what I was looking for.
Thanks from me and my colleges!
October 18, 2009 at 4:30 pm
From the original MIX code I also Updated the reference and noted that it then failed to build as it added the following to the Reference:
public System.Net.CookieContainer CookieContainer {
Which throws up a type namespace error.
How do I fix this please?
October 18, 2009 at 4:34 pm
Nevermind, I just added the reference, I figured this would have already been included.