Channels ▼
RSS

.NET

Pushing Data to a Silverlight Client with a WCF Duplex Service: Part I


Dan Wahlin (Microsoft Most Valuable Professional for ASP.NET and XML Web Services) is a .NET development instructor and architecture consultant at Interface Technical Training. Dan founded the XML for ASP.NET Developers site, which focuses on using ASP.NET, XML, Silverlight, AJAX, and Web Services on .NET and runs smartwebcontrols.com. He's also on the INETA Speaker's Bureau and speaks at several conferences. Dan has co-authored/authored several different books on .NET, including ASP.NET 2.0 MVP Hacks, Professional ASP.NET AJAX, XML for ASP.NET Developers and is currently working on a new book on Silverlight 2. Dan blogs at http://weblogs.asp.net/dwahlin.

Silverlight provides several different ways to access data stored in remote locations. Data can be pulled from Web Services and RESTful services and even pushed from servers down to clients using sockets:

Silverlight 2 Beta 2 introduces another way to push data from a server to a client using Windows Communication Foundation (WCF) and HTTP. WCF's support for duplex service contracts makes this possible and opens up unique opportunities for pumping data to Silverlight clients. In this first part of a two-part article, I demonstrate how a WCF push service can be created and cover the steps to get a sample service up and running. In Part II, I focus on the client and show how to communicate with a WCF duplex service and listen for data that's sent

Many of the WCF services out there follow the simple request-response mechanism to exchange data which works well for many applications. However, in addition to standard HTTP bindings, WCF also supports several others including a polling duplex binding made specifically for Silverlight which allows a service to push data down to a client as the data changes. This type of binding isn't as "pure" as the push model available with sockets since the Silverlight client does poll the server to check for any queued messages, but it provides an efficient way to push data to a client without being restricted to a specific port range. Once a communication channel is opened messages can be sent in either direction. The Silverlight SDK states the following about how communication works between a Silverlight client and a duplex service:

The Silverlight client periodically polls the service on the network layer, and checks for any new messages that the service wants to send on the callback channel. The service queues all messages sent on the client callback channel and delivers them to the client when the client polls the service.

Creating Contracts

When creating a WCF duplex service for Silverlight, the server creates a standard interface with operations. However, because the server must communicate with the client it also defines a client callback interface. Here is an example of defining a server interface named IGameStreamService that includes a single service operation:

[ServiceContract(Namespace = "Silverlight", CallbackContract = typeof(IGameStreamClient))]
public interface IGameStreamService
{
    [OperationContract(IsOneWay = true)]
    void GetGameData(Message receivedMessage);
}

This interface is a little different from the standard WCF interfaces you may have seen or created. First, it includes a CallbackContract property that points to the client interface. Second, the GetGameData() operation is defined as a one way operation. Client calls are not immediately returned as a result of setting IsOneWay to true and are pushed to the client instead. The IGameStreamClient interface assigned to the CallbackContract is shown next. It lets a message be sent back to the client by calling the ReceiveGameData() method.

[ServiceContract]
public interface IGameStreamClient
{
    [OperationContract(IsOneWay = true)]
    void ReceiveGameData(Message returnMessage);
}

Creating the Service

Once the server and client contracts are defined a service class can be created that implements the I GameStreamService interface. The following code creates a service that simulates a basketball game (similar to the one I demonstrated for using Sockets with Silverlight) and sends game updates to a Silverlight client on a timed basis.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading;

namespace WCFPushService
{
    public class GameStreamService : IGameStreamService
    {
        IGameStreamClient _Client;
        Game _Game = null;
        Timer _Timer = null;
        Random _Random = new Random();

        public GameStreamService()
        {
            _Game = new Game();
        }

        public void GetGameData(Message receivedMessage)
        {

            //Get client callback channel
            _Client = OperationContext.Current.GetCallbackChannel<IGameStreamClient>();

            SendData(_Game.GetTeamData());
            //Start timer which when fired sends updated score information to client
            _Timer = new Timer(new TimerCallback(_Timer_Elapsed), null, 5000, Timeout.Infinite);
        }

        private void _Timer_Elapsed(object data)
        {
            SendData(_Game.GetScoreData());
            int interval = _Random.Next(3000, 7000);
            _Timer.Change(interval, Timeout.Infinite);
        }

        private void SendData(object data)
        {
            Message gameDataMsg = Message.CreateMessage(
                MessageVersion.Soap11,
                "Silverlight/IGameStreamService/ReceiveGameData", data);

            //Send data to the client
            _Client.ReceiveGameData(gameDataMsg);
        }
    }
}

The service first creates an instance of a Game class in the constructor which handles simulating a basketball game and creating new data that can be sent to the client. Once the client calls the service's GetGameData() operation (a one-way operation), access to the client's callback interface is retrieved by going through the OperationContext object and calling the GetCallbackChannel() method. The teams involved in the game are then created on the server and pushed to the client by calling the SendData() method. This method calls the Game object's GetTeamData() method. Although not shown here (but included in the sample code), the GetTeamData() method generates an XML message and returns it as a string. The SendData() method then creates a WCF Message object, defines that SOAP 1.1 will be used (required for this type of communication) and defines the proper action to be used to send the XML data to the client. The client's ReceiveGameData() operation is then called and the message is ultimately sent to the client.

Once the client receives the team data the server will start sending simulated score data on a random basis. When the Timer object created in the initial call to GetGameData() fires the _Timer_Elapsed() method is called which gets updated score information and pushes it to the Silverlight client by calling the SendData() method.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video