Geeks With Blogs
Peter Tweed Exploring and explaining the mysteries of .NET

A very useful feature in is the ability to use duplex services, so that the server can send messages to the Silverlight client.  This is really useful when the server should control the when the messages are sent and pushed to clients as opposed to the client having to manage the code to regularly poll a service to find out if the state it is interested in has changed.

 

In this post I we will implement a simple duplex service.  The service will allow a user to register to receive stock updates for MSFT or YHOO.  Once the client is registered the WCF service will send the Silverlight client updates every 5 seconds.  The user will also be able to call a non duplex function within the same WCF service to get an update when they want it – showing that duplex and non duplex servie methods can be implemented in the same service.

 

This app is built on Visual Studio 2008 SP1, Silverlight 3 and the Silverlight Toolkit using C#.

Steps:

 

1.       Create a new Silverlight application named Duplex.

2.       Choose to add a test web application (Duplex.Web) for the new solution.

3.       Add a WCF service to the web project

 

4.       Add a reference to the file %Program Files%\Microsoft SDKs\Silverlight\v3.0\Libraries\Server\System.ServiceModel.PollingDuplex.dll in your web project.  Ensure you use the assembly under the SERVER directory in the above path.

5.       In the WCF Service generated interface file IDuplexSvc.cs replace the existing interface with the following code

 

    [ServiceContract(Namespace = "Silverlight", CallbackContract = typeof(IDuplexSvcClient))]

    public interface IDuplexSvc

    {

        [OperationContract(IsOneWay = true)]

        void RegisterForStockUpdates(String ticker);

 

        [OperationContract()]

        Stock GetStockUpdate();

    }

 

    [ServiceContract]

    public interface IDuplexSvcClient

    {

        [OperationContract(IsOneWay = true)]

        void StockUpdated(Stock stock);

    }

 

IDuplexSvc is the interface for the WCF service on the server that the Silverlight client will call into.  Note the CallbackContract attribute defines the contract the duplex service will use to call back to the Silverlight client - IDuplexSvcClient.

 

Also note the RegisterForStockUpdates function has the attribute IsOneWay = true.  This defines that the caller will not wait for a response from the WCF service before continuing.  That said in Silverlight all out of process calls are asynchronous anyway.

 

I have also added a GetStockUpdate function that is not one way that returns immediately the stock information that the user requests – rather than the user waiting for the duplex call.  We’ll hook all this up later with the Silverlight UI.

 

In the IDuplexSvcClient interface we have the StockUpdated function, which is what the server uses to call the client.  It is also one way as we don’t want the server to wait for a response from the client.  The client must handle this function to receive the updated stock updates from the server when the server makes a duplex call to the client.

 

6.       In the DuplexSvc.cs file in the web project replace the DuplexSvc class with this updated code

 

    public class DuplexSvc : IDuplexSvc

    {

        IDuplexSvcClient client;

        String registeredTicker;

        Timer updateClient = null;

 

        #region IDuplexSvc Members

 

        public void RegisterForStockUpdates(String ticker)

        {

            client = OperationContext.Current.GetCallbackChannel<IDuplexSvcClient>();

            registeredTicker = ticker;

            updateClient = new Timer(5000);

            updateClient.Elapsed += new ElapsedEventHandler(updateClient_Elapsed);

            updateClient.Enabled = true;

            updateClient.Start();

        }

 

        public Stock GetStockUpdate()

        {

            Stock stock = new Stock();

            stock.StockTicker = registeredTicker;

 

            switch (registeredTicker)

            {

                case "MSFT":

                    stock.CompanyName = "Microsoft Corporation";

                    Random randM = new Random();

                    stock.StockValue = randM.Next(20,30);

                    break;

                case "YHOO":

                    Random randY = new Random();

                    stock.StockValue = randY.Next(10,20);

                    stock.CompanyName = "Yahoo! Inc";

                    break;

                default:

                    stock.CompanyName = "[Unknown]";

                    break;

            }

 

            return stock;

        }

 

        #endregion

 

        void updateClient_Elapsed(object sender, ElapsedEventArgs e)

        {

            client.StockUpdated(GetStockUpdate());

        }

 

    }

 

    public class Stock

    {

        public double StockValue;

        public String StockTicker;

        public String CompanyName;

        public String StockTime = DateTime.Now.ToLongTimeString();

    }

 

This code has two classes – the implemented DuplexSvc and the Stock class that will be used to hold the stock info and return it to the client in both the duplex and non duplex functions.

 

When the client calls the RegisterForStockUpdates function a reference to the calling client is retrieved using

 

 

            client = OperationContext.Current.GetCallbackChannel<IDuplexSvcClient>();

 

This allows the service object to retain a reference to the calling client for making duplex calls back to the client when the timer (created next)  fire it’s elapsed event.  Next the stock ticker string is recorded and a class timer is instantiated with an interval of 5 seconds.  The timer calculates a new stock update (in GetStockUpdate – declares a stock object with the ticker name, the appropriate company name and a random generated stock value).  The timer elapsed handler then calls the client.StockUpdated function passing the calculated stock object as a parameter.  Therefore in our example the server calls the client every fix seconds with updated stock information for the stock requested by the client.

 

Also don’t forget that the GetStockUpdate function is part of our service interface and can be called by the client directly to retrieve a new stock update any time.

 

7.        Build the web project

8.       Add a service reference to the Silverlight project for the DuplexSvc

 

 

9.       Add a reference to the file %Program Files%\Microsoft SDKs\Silverlight\v3.0\Libraries\Client\System.ServiceModel.PollingDuplex.dll in your web project.  Ensure you use the assembly under the CLIENT directory in the above path.

10.   In the MainPage.xaml file in the Silverlight project copy the following XAML

 

  <Grid x:Name="LayoutRoot" Background="LightBlue" >

        <Grid.RowDefinitions>

            <RowDefinition Height="30"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="100"></ColumnDefinition>

            <ColumnDefinition Width="*"></ColumnDefinition>

        </Grid.ColumnDefinitions>

        <TextBlock Grid.Column="0" Grid.Row="0" Text="Stock Ticker:"></TextBlock>

        <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="0" >

            <ComboBox x:Name="StockSelector">

                <ComboBoxItem Content="MSFT"></ComboBoxItem>

                <ComboBoxItem Content="YHOO"></ComboBoxItem>

            </ComboBox>

            <Button x:Name="btnRegisterTicker" Content="Register Stock" Click="btnRegisterTicker_Click" />

            <Button x:Name="btnGetUpdate" Content="Get Update" Click="btnGetUpdate_Click"  Visibility="Collapsed"  />

        </StackPanel>

        <TextBlock Grid.Column="0" Grid.Row="1" Text="Stock History:"></TextBlock>

        <ListBox x:Name="lstStockHistory" Width="200" Height="200" Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Visible"  >

            <ListBox.ItemTemplate>

                <DataTemplate>

                    <Border BorderBrush="CadetBlue" BorderThickness="3" CornerRadius="3" Width="170" >

                        <StackPanel Orientation="Vertical" >

                            <StackPanel Orientation="Horizontal">

                                <TextBlock Text="{Binding StockTicker}" />

                                <TextBlock Text=": " />

                                <TextBlock Text="{Binding StockValue}" />

                            </StackPanel>

                            <TextBlock Text="{Binding CompanyName}" />

                            <TextBlock Text="{Binding StockTime}" Foreground="DarkOrange" FontSize="14" />

                        </StackPanel>

                    </Border>

                </DataTemplate>

            </ListBox.ItemTemplate>

        </ListBox>

  </Grid>

 

This provides our UI.  A combo box will allow the user to select MSFT or YHOO as the stock.  The user then clicks the Register Stock button.  The list box will show the details of the stock object retrieved from the WCF service – via the bound data template.  The user can also use the Get Update button to retrieve a stock update immediately.

 

11.   In the MainPage.xaml.cs file in the Silverlight project replace the MainPage class with the following code

 

    public partial class MainPage : UserControl

    {

        DuplexSvcClient proxy = null;

        System.Collections.ObjectModel.ObservableCollection<Stock> stockHistory = new System.Collections.ObjectModel.ObservableCollection<Stock>();

 

        public MainPage()

        {

            InitializeComponent();

            this.Loaded += new RoutedEventHandler(MainPage_Loaded);

        }

 

        void MainPage_Loaded(object sender, RoutedEventArgs e)

        {

            EndpointAddress svcAddress = new EndpointAddress("http://localhost:49346/DuplexSvc.svc");

 

            PollingDuplexHttpBinding svcBinding = new PollingDuplexHttpBinding();

           

            proxy = new DuplexSvcClient(svcBinding, svcAddress);

 

            proxy.RegisterForStockUpdatesCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>((o, ev) => {

                btnGetUpdate.Visibility = Visibility.Visible;

            });

            proxy.StockUpdatedReceived+=new EventHandler<StockUpdatedReceivedEventArgs>((o,ev)=> {

                UpdateStockHistory(ev.stock);

            });

            proxy.GetStockUpdateCompleted += new EventHandler<GetStockUpdateCompletedEventArgs>((o, ev) => {

                Stock stock = ev.Result as Stock;

                UpdateStockHistory(stock);

            });

        }

 

        private void UpdateStockHistory(Stock stock)

        {

            stockHistory.Add(stock);

            Dispatcher.BeginInvoke(new Action(() => {

                lstStockHistory.ItemsSource = stockHistory;

                if (stockHistory.Count > 1)

                {

                    Array stocks = stockHistory.ToArray();

                    if (stockHistory[stockHistory.Count - 1].StockValue > stockHistory[stockHistory.Count - 2].StockValue)

                        lstStockHistory.Background = new SolidColorBrush(Colors.Green);

                    else if (stockHistory[stockHistory.Count - 1].StockValue == stockHistory[stockHistory.Count - 2].StockValue)

                        lstStockHistory.Background = new SolidColorBrush(Colors.White);

                    else

                        lstStockHistory.Background = new SolidColorBrush(Colors.Red);

                }

                lstStockHistory.ScrollIntoView(stock);

            }));

        }

 

        private void btnRegisterTicker_Click(object sender, RoutedEventArgs e)

        {

            ComboBoxItem item = StockSelector.SelectedItem as ComboBoxItem;

            string ticker = item.Content as string;

 

            proxy.RegisterForStockUpdatesAsync(ticker);

            btnRegisterTicker.Visibility = Visibility.Collapsed;

        }

 

        private void btnGetUpdate_Click(object sender, RoutedEventArgs e)

        {

            proxy.GetStockUpdateAsync();

        }

    }

 

In this updated class we define a proxy to the WCF service and an ObservableCollection of stock object that will be used to hold all the stock object retrieved from the web service either through duplex communication or as a response to GetStockUpdate.

 

When the MainPage is loaded we instantiate our proxy defining the endpoint address and the binding of PollingDuplexHttpBinding – this binding enables the duplex functionality we require.  The callback handlers are then defined for the RegisterForStockUpdatesCompleted, StockUpdatedReceived and GetStockUpdateCompleted events.

 

Note – the StockUpdatedReceived handler handles the duplex call from the service when the timer fires every 5 seconds.  The naming convention for such handlers is <function defined in client callback interface>Received.

 

The handler for the RegisterForStockUpdatesCompleted makes the Get Update button visible.

 

The StockUpdatedReceived and GetStockUpdateCompleted handlers pass the stock object received respectively to UpdateStockHistory which updates the UI.  Note the use of Dispatcher to ensure the work done to interact with the UI is done on the UI thread.  The function adds the stock info to the observable collection to record all instances of the stock info received and then the observable collection is set to the itemssource of the list box to bind the entries.  We also have some logic to change the color of the list box – if the stock went up since the last stock update make the background green, if the stock went down make the background red.

 

The Register Stock button handler gets the ticker selected from the combo box and calls the RegisterForStockUpdates function in the WCF service – which starts the timer to perform duplex call backs to the client with stock info.  It also hides the Register Stock button to stock the user from registering twice.

 

Finally the Get Update button handler calls the GetStockUpdate WCF service to immediately retrieve stock information.

 

12.   Build and run the application

 

 

13.   Select MSFT or YHOO and click the Register Stock button

 

 

Wait and you will receive updates to your chosen stock every 5 seconds with the color of the list box changing appropriately.

 

14.   Click the Get Update button and you’ll receive an update immediately

 

 

Congratulations!!!! You have created your own application with duplex WCF services where the server calls the client to provide updates.

 

What have we done?

 

We have defined a WCF service that implements duplex and non duplex methods.

 

We have implemented a Silverlight application that consumes both the duplex and non duplex functionality of the WCF service.

 

Conclusion

Silverlight has a good mechanism for using duplex WCF services.  Although behind the scenes the WCF duplex service infrastructure for Silverlight uses a polling mechanism, you do not need to worry about those details.  By simply defining your normal WCF interfaces, implementation and appropriate binding, you can take advantage of the server calling the client once the client has registered with the service.

 

Posted on Tuesday, July 28, 2009 10:15 PM Silverlight | Back to top


Comments on this post: Server calling the client - duplex WCF Services in Silverlight

# re: Server calling the client - duplex WCF Services in Silverlight
Requesting Gravatar...
Could you be able to update the source code for this application?
Left by Sean on Aug 14, 2009 12:02 AM

# re: Server calling the client - duplex WCF Services in Silverlight
Requesting Gravatar...
The cource code can be downloaded from http://www.creativetweed.com/blogging/files/duplex.zip.
Left by Peter on Aug 16, 2009 10:08 PM

# re: Server calling the client - duplex WCF Services in Silverlight
Requesting Gravatar...
Download link doesnt work. Can you please provide me your source code?
Left by Nojo on Jun 15, 2010 7:41 AM

# re: Server calling the client - duplex WCF Services in Silverlight
Requesting Gravatar...
Hi Nojo - make sure you don't have the dot at the end of the link; i.e. use

http://www.creativetweed.com/blogging/files/duplex.zip

it works fine

Left by Peter on Jun 15, 2010 10:59 PM

# re: Server calling the client - duplex WCF Services in Silverlight
Requesting Gravatar...
WCF is unable to browse the WCF service when code built as per your instructions. The error is: "Contract requires Duplex, but Binding 'WSHttpBinding' doesn't support it or isn't configured properly to support it."

Are you sure you didnt miss to document web.config related changes?
Left by James on Jun 27, 2011 4:42 AM

# re: Server calling the client - duplex WCF Services in Silverlight
Requesting Gravatar...
Your sample works! thanks! However you missed mentioning about web.config changes in your blog post.
Left by Pavan on Jun 27, 2011 8:13 AM

# re: Server calling the client - duplex WCF Services in Silverlight
Requesting Gravatar...
The source is not available anymore. Can you put it back please?

http://www.creativetweed.com/blogging/files/duplex.zip
Left by Werner on Jan 23, 2012 5:22 AM

# re: Server calling the client - duplex WCF Services in Silverlight
Requesting Gravatar...
Please provide the source code, i am getting error on web.config.

How to configure that.....???
Left by Kumar on Mar 15, 2013 9:30 PM

# re: Server calling the client - duplex WCF Services in Silverlight
Requesting Gravatar...
if we refreshed the web page that host the silverlight application, will it still have the same ICallbackClient object ?
and if no will the old one just vanish or i should handle it manually ?
Thank you very much
Left by aymanXoXo on Dec 09, 2015 8:26 AM

Your comment:
 (will show your gravatar)


Copyright © PeterTweed | Powered by: GeeksWithBlogs.net