Services and data access are the focus of the book I’m writing (more very very soon!). Working with services to get data into a Silverlight application is so vital, it should be code that’s known by every Silverlight developer by heart. Working with duplex bindings is somewhat more complicated. However, there are situations in which duplex communication is really necessary. Think of the typical example: a stock application that should send stock updates to the client without the client requesting for an update.
Duplex communications are possible with WCF. They “seem” initiated by the server: the service will send updates without the client requests the service to do so. This way, the client can receive updates whenever new information is available on the server (new stock info that becomes available) and act accordingly. I put seem between quotes. The reason for that is that a duplex binding is in fact still a normal request/receive process. Initially, the client has to do a request to the service and from then on, the service can send its updates to the client.
In the example I have created for this post, I created an application that posts updates about snow throughout Belgium (while writing this article, it has snowed quite a lot in Belgium, so that’s where the inspiration came from and Tienen is where I live :) ). Below is a screenshot.
Of course, you’re here to learn something and see some code, right? No problem! Let’s first focus on the service. For the data exchange, I created a small type called SnowUpdate.
public class SnowUpdate
{
public string Location { get; set; }
public double centimeter { get; set; }
}
One very important thing that we need to do, is adding a reference to an assembly available in the Silverlight SDK called System.Service.PollingDuplex.dll. By default, it’s installed in C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\Server. Add a reference to this assembly. (Note the x86, that’s because I’m running 64bit).
The contract of the service makes it clear that we are working with a duplex service. There are some special things to note in this code. As you can see, two interfaces are defined here. The first one is the regular contract, the second one is what’s called the callback contract and defines the contract for the call to the client.
Also note that both OperationContracts have IsOneWay set to true. For the Connect method, we’re actually saying: a client can call Connect to make itself known to the service but it expects no response, hence the IsOneWay.
[ServiceContract(Namespace = "Silverlight", CallbackContract = typeof(ISnowServiceClient))]
public interface ISnowService
[OperationContract(IsOneWay = true)]
void Connect();
[ServiceContract]
public interface ISnowServiceClient
void SendSnowUpdate(SnowUpdate snowUpdate);
In the service implementation, I have created a Timer, which will periodically send a new message to the client. The OperationContext.Current.GetCallbackChannel gives us access to the callback channel which we can use to send messages to the client side. On a tick of the Timer, we’re sending a message.
private ISnowServiceClient client;
private Timer timer;
public void Connect()
client = OperationContext.Current.GetCallbackChannel<ISnowServiceClient>();
timer = new Timer(new TimerCallback(TimerTick), null, 500, 5000);
void TimerTick(object state)
try
if (client != null)
client.SendSnowUpdate(GetLatestUpdate());
catch (Exception)
client = null;
timer.Dispose();
With that, the service code is done, but it does require some specific configuration code to work. Take a look at the sample for this code. We can now look at the client code. The process to add a service reference is exactly the same, although you’ll notice that the ServiceReferences.clientconfig file remains empty (which it does not when referencing a normal service). Therefore, the code that we need to write is somewhat more complex: we have to create the binding and the address from code and pass this along with the proxy instantiation. Below you can see the client-side code.
private void UserControl_Loaded(object sender, RoutedEventArgs e)
EndpointAddress address = new EndpointAddress("http://localhost:59485/SnowService.svc");
CustomBinding binding = new CustomBinding(
new PollingDuplexBindingElement(),
new BinaryMessageEncodingBindingElement(),
new HttpTransportBindingElement());
client = new SLDuplexSnow.SnowService.SnowServiceClient(binding, address);
client.SendSnowUpdateReceived +=
new EventHandler<SLDuplexSnow.SnowService.SendSnowUpdateReceivedEventArgs>
(client_SendSnowUpdateReceived);
client.ConnectAsync();
void client_SendSnowUpdateReceived(object sender,
SLDuplexSnow.SnowService.SendSnowUpdateReceivedEventArgs e)
SnowDetailsGrid.DataContext = e.snowUpdate;
Note that we are calling ConnectAsync to let the service know about the client so it can send updates to it BUT we are handing SnowUpdateReceived events.
NOTE: This sample is written for Silverlight 3/VS2008. At this point, I have issues with VS2010 when generating the client proxy with SL4/VS2010 when using a duplex service.
The complete code can be downloaded here: SLDuplex.zip (111.91 KB)
All content is property of www.snowball.be. Nothing on this site can be copied or published elsewhere, unless otherwise stated.
This site is made by Gill Cleeren.
Questions? Opinions? E-mail