Configuring WCF services programmatically for Silverlight

So, like always there was this rather strange problem I came across a couple of days ago. For most normal applications I would be more than happy to just configure my WCF services in the web.config/app.config file. The annoying XML for System.ServiceModel has become quite friendly with me. But the situation now was that I was working on a silverlight application and I had to modify the binding dynamically. Some crazy requirements require my Silverlight application to start using a different service endpoint based on some internal events. The first thing I had to do was shoot out the idea of having the nice friendly config file, delete it off my project and create a code to generate an impromptu binding each time the service is requested.

My normal way of creating a binding configuration is to set all the string and buffer lengths to maximum. (Atleast, the application Im working on requires this). One of the important things that need to be set to max value is the ReaderQuota:

[XML config sample]

So I tried to do this programmatically and guess what?! In Silverlight the XmlDictionaryReaderQuotas object that is required to define the ReaderQuota cannot be instantiated. Now, how the heck am I supposed to create it? Not just that, there is not direct way to set the “ReaderQuota” property of the BasicHttpBinding. The only way to set that property is to use Reflection!

First of all creating a decent configuration file in Silverlight is a pain and on top of that you can even set the values programmaticaly. Were the creators of Silverlight 4.0 drunk when they designed the configuration module?

Anyway, here is how you set up the ReaderQuotas with “MAXIMUM” reader sizes for a WCF binding in Silverlight:

BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
binding.CloseTimeout = new TimeSpan(00, 05, 00);
binding.OpenTimeout = new TimeSpan(00, 05, 00);
binding.ReceiveTimeout = new TimeSpan(00, 05, 00);
binding.SendTimeout = new TimeSpan(00, 05, 00);
binding.TextEncoding = System.Text.Encoding.UTF8;
binding.MaxReceivedMessageSize = int.MaxValue;
binding.MaxBufferSize = int.MaxValue;             

binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, XmlDictionaryReaderQuotas.Max, null);

Hopefully this will help someone out. In fact it was not that tough to Google this solution out, but the implications of this solution just irked me into writing this post.

Live Twitter messages on Silverlight 4 through WCF Push

In this post I’ll share a small fun application that fetches live messages from Twitter and displays it in Silverlight using WCF Push technology. A topic I’ll discuss in particular in this topic is the WCF Duplex model. The twitter library Im using is called Yedda. Thanks to the creators of Yedda. Its very simple and easy to use. You can visit their site at http://yedda.com/ . We’ll be downloading their Twitter Wrapper later, If you’re in too much of a hurry go download it right now. So, lets get coding tweeps…

1. Create a Simple Silverlight Form

First Im going to create a New Silverlight Project called FunWithTwitter. Visual Studio 2010 is going to ask us if we want to create a Web project along with it. Yes, we do want it to create a web project. First we’ll make a very simple interface to show the text messages. We’ll only use a text block. No need for any fancy XAML here. We’re more interested in the service side right now.

<UserControl x:Class="FunWithTwitter.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot">
        <Border Margin="20" BorderBrush="#B8343434" CornerRadius="10" BorderThickness="1">
            <Border.Background>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="White" Offset="0" />
                    <GradientStop Color="#FFDEDEDE" Offset="1" />
                </LinearGradientBrush>
            </Border.Background>
                <Grid Margin="25">
                <Grid.RowDefinitions>
                    <RowDefinition Height="30" />
                    <RowDefinition Height="1*" />
                </Grid.RowDefinitions>
                <StackPanel Grid.Row="0" Orientation="Horizontal">
                    <Button Content="Invoke" Width="100" HorizontalAlignment="Left" VerticalAlignment="Stretch" Margin="0,0,10,0" />
                    <TextBlock x:Name="TxtStatus" HorizontalAlignment="Left" Text="Application starting..." VerticalAlignment="Center" />
                </StackPanel>
                <ScrollViewer Grid.Row="1">
                    <TextBlock x:Name="TxtTweets" />
                </ScrollViewer>
            </Grid>
        </Border>
    </Grid>
</UserControl>

In the above form, the big TextBlock with the scroll bar (TxtTweets) is where we will populate the tweets. The TextBlock at the top (TxtStatus) will show a timestamp that displays the time the last message was received. The Button is used to invode the service.

2. Add Twitter API

Now is the time we download the Yedda library from http://devblog.yedda.com/wp-content/uploads/2007/05/yeddatwitter-v01.zip. You’ll be downloading a standard visual studio project. Copy that project to the same folder where your current project FunWithTwitter is located. (If required create a folder Yedda here). In visual studio > Solution (context menu) > Add existing project – select the .csproj file from the Yedda folder that you just copied the files into. This will be the third project to your solution. You’ll not be touching this project again, so you can collapse it and forget it.

Now on your FunWithTwitter.Web project add a reference to the Yedda Project. You’re all set to start consuming RSS from Twitter.

3. Write the WCF Service

Now this is the biggest part of the project. Do this with a bit of patience and read your reference material carefully. I’ve often found myself skipping straight to the sample code and not reading the description and then ending up googling to get the answer back in the same place I started off with. So… We’ll first add a new Silverlight Enabled WCF Service to our FunWithTwitter.Web project. I’ll name my file TwitterService.svc. Here we’ll be doing 3 things – Adding Library Reference, Creating the service, Configuring the service.

Add the additional references

Right click on your references folder in FunWithTwitter.Web project. In the .NET tab check if you have a reference for:

System.Linq;System.ServiceModel.PollingDuplex

If you don’t, go to the ‘Browse’ tab and the the DLL at the following location:

C:\Program Files\Microsoft SDKs\Silverlight\v4.0\Libraries\Server\System.ServiceModel.PollingDuplex.dll

Now you should have the required libraries to run the WCF Service. (We’ll be adding a reference like this to the Silverlight project later)

Create the service

Creating the service is quite easy actually. Just copy and paste the code below 🙂 [A detailed explanation of this is at the end of the post]

using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Threading;
using System.Xml.Linq;

namespace FunWithTwitter.Web
{
    [ServiceContract(Namespace = "", CallbackContract = typeof(ISessionClient))]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class TwitterService
    {
        ITwitterClient client;

        [OperationContract(IsOneWay = true)]
        public void Startup()
        {
            client = OperationContext.Current.GetCallbackChannel<ITwitterClient>();

            // A timer that calls the SendRandomString function once every 10 seconds
            Timer t = new Timer(new TimerCallback(StreamTweets), new AutoResetEvent(false), 0, 10000);
        }

        // A function that gets the friends timeline, converts it to plaintext and sends it to the client
        private void StreamTweets(object State)
        {
             string ClientMessage = "";

            Yedda.Twitter t = new Yedda.Twitter();

            XDocument xDoc = XDocument.Parse(t.GetFriendsTimeline("shishir305", "*****", Yedda.Twitter.OutputFormatType.RSS));

            foreach (XElement item in xDoc.Element("rss").Element("channel").Elements("item"))
            {
                ClientMessage += item.Element("description").Value + "\r\r";
            }

            // The actual client callback
            client.RecentTweets(ClientMessage);
        }
    }

    [ServiceContract]
    public interface ITwitterClient
    {
        [OperationContract(IsOneWay = true)]
        void RecentTweets(string tweets);
    }
}

First, you should notice the CallbackContract = typeof(ITwitterClient) in the [ServiceContract]. This tell the WCF service that call back contract is defined by the ITwitterClientInterface.
Second, you should notice the IsOneWay = true statements in the [OperationContract]. This will tell the service that this is a one way operation. i.e., data will be passed continuously from one endpoint of the connection to the other. (There are three modes in WCF / Silverlight – OneTime(default), OneWay, TwoWay).
Third, you should notice the client = OperationContext.Current.GetCallbackChannel<ITwitterClient>(); statement. This is the place where the service comes to know who the client is and stores a reference to the client in the client object. This is generally the toughest part in a Duplex connection. Getting the service to know who the client is. Thanks to System.ServiceModel.PollingDuplex, this has been reduced to one line for us.

Once you have understood the three things we have done, you are almost done with Duplex connections. The next few lines are just some flashy timers that call the StreamTweets function to run over and over, there by sending a stream of data to the client. You will soon notice that the client is simply sitting at one place and displaying data whenever the service sends some.

Fourth, Notice the client.RecentTweets(ClientMessage); in the StreamTweets function. This is where the server sends the data to the client.

Configure the service

You should be very careful when you are configuring the service. This is the configuration that goes in your web.config or your app.config. The code below shows the configuration that should go into this. You can just copy and replace your settings in your config file.

Note the following changes:
1. We added pollingDuplexHttpBinding as a binding extension. For this you need to make sure

    <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>

      <behaviors>
        <serviceBehaviors>
          <behavior name="">
            <serviceMetadata httpGetEnabled="true" />
            <serviceDebug includeExceptionDetailInFaults="false" />
          </behavior>
        </serviceBehaviors>
      </behaviors>

      <bindings>
        <pollingDuplexHttpBinding />
      </bindings>

      <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

      <services>
        <service name="FunWithTwitter.Web.TwitterService" >
          <endpoint address="" binding="pollingDuplexHttpBinding" contract="FunWithTwitter.Web.TwitterService" />
          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
      </services>

    </system.serviceModel>

Once you have the service configured, build the application and make sure its working.

4. Consume the service

Finally we create the client:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using FunWithTwitter.TwitterServiceProxy;
using System.ServiceModel;

namespace FunWithTwitter
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            PollingDuplexHttpBinding binding = new PollingDuplexHttpBinding();
            EndpointAddress remoteAddress = new EndpointAddress("http://localhost:54643/TwitterService.svc");

            TwitterServiceClient proxy = new TwitterServiceClient(binding, remoteAddress);

            proxy.RecentTweetsReceived += new EventHandler<RecentTweetsReceivedEventArgs>(proxy_RecentTweetsReceived);

            proxy.StartupCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(proxy_StartupCompleted);
            proxy.StartupAsync();
        }

        void proxy_StartupCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                TxtStatus.Text = "Error initializing application";
            }
            else
            {
                TxtStatus.Text = "Application successfully initialized";
            }
        }

        void proxy_RecentTweetsReceived(object sender, RecentTweetsReceivedEventArgs e)
        {
            if (e.Error != null)
            {
                TxtStatus.Text = "Error receiving tweets";
            }
            else
            {
                TxtStatus.Text = "Updates received @ " + DateTime.Now.ToString("T");
                TxtTweets.Text = e.tweets;
            }
        }
    }
}

Consuming WCF Services from Silverlight 4

There are several ways to perform Data Access with Silverlight 4. One of the best ways is to use a WCF Service. One of the biggest advantages of using WCF services is that the Business Objects [Data Contracts] can be mapped exactly with your Silverlight Applications’ View-Model. In this tutorial I will start with a Silverlight form and then create a service. In real-life senario, you’ll probably create a form based on a service. But for now, lets first start with the Silverlight 4 Form.

Create a Silverlight Form – First open Visual Studio 2010 and start a new Silverlight application in a new project. (Life’s much easier if you use some good naming convention. I’ll name my application SilverlightWcf). You will be asked if you want to create a web project along with this. I’d agree to that and let it create a SilverlightWcf.Web project. In the SilverlightWcf project, create a form that’s something like the one shown below. Just copy and paste the XAML in your MainPage.xaml.

<Grid x:Name="LayoutRoot" Background="White" Width="400" Height="300">
    <Border Margin="20" BorderBrush="#B8343434" CornerRadius="10" BorderThickness="1">
        <Border.Background>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="White" Offset="0" />
                <GradientStop Color="#FFDEDEDE" Offset="1" />
            </LinearGradientBrush>
        </Border.Background>
        <Grid Margin="20">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="3*" />
                <ColumnDefinition Width="5*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="25" />
                <RowDefinition Height="25" />
                <RowDefinition Height="25" />
                <RowDefinition Height="25" />
                <RowDefinition Height="25" />
                <RowDefinition Height="25" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="1" Grid.RowSpan="1" HorizontalAlignment="Left" Margin="0" Name="textBlock1" Text="Name" VerticalAlignment="Center" Width="120" />
            <TextBlock Grid.Row="2" Grid.RowSpan="1" HorizontalAlignment="Left" Margin="0" Name="textBlock2" Text="Location" VerticalAlignment="Center" Width="120" />
            <TextBlock Grid.Row="3" Grid.RowSpan="1" HorizontalAlignment="Left" Margin="0" Name="textBlock3" Text="Group" VerticalAlignment="Center" Width="120" />

            <TextBox x:Name="TxtName" Grid.Column="1" Grid.Row="1" Grid.RowSpan="1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="120" />
            <ComboBox x:Name="CmbLocation" Grid.Column="1" Grid.Row="2" Grid.RowSpan="1" Height="23" HorizontalAlignment="Left" VerticalAlignment="Center" Width="120" >
                <ComboBox.Items>
                    <ComboBoxItem Content="Gondor" />
                    <ComboBoxItem Content="Rohan" />
                    <ComboBoxItem Content="Mordor" />
                    <ComboBoxItem Content="The Shire" />
                </ComboBox.Items>
            </ComboBox>
            <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="3" >
                <RadioButton x:Name="RdbMen" Content="Man" HorizontalAlignment="Left" VerticalAlignment="Center" GroupName="grpGroupType" Margin="0,0,5,0" />
                <RadioButton x:Name="RdbElf" Content="Elf" HorizontalAlignment="Left" VerticalAlignment="Center" GroupName="grpGroupType" Margin="0,0,5,0" />
                <RadioButton x:Name="RdbHobbit" Content="Hobbit" HorizontalAlignment="Left" VerticalAlignment="Center" GroupName="grpGroupType" Margin="0,0,5,0" />
            </StackPanel>

            <CheckBox x:Name="ChkOwnRing" Content="I own a ring of power" Grid.Column="1" Grid.Row="4" Height="16" HorizontalAlignment="Left" VerticalAlignment="Center" VerticalContentAlignment="Top" />
            <Button x:Name="BtnSubmit" Content="Submit" Grid.Column="1" Grid.Row="5" Grid.RowSpan="1" Height="23" HorizontalAlignment="Left" VerticalAlignment="Center" Width="75"
                Click="BtnSubmit_Click" />

            <TextBlock x:Name="TxtMessage" Text="[Message]" Grid.Row="7" FontWeight="Bold" Grid.ColumnSpan="2" HorizontalAlignment="Left" Width="318" TextWrapping="Wrap"></TextBlock>
        </Grid>
    </Border>
</Grid>

This is how the form is going to work. We will provide the values that are required and our service returns a message that we’ll display at the bottom. But remember, we’ll be transferring specific business objects through our service. Based on the form above, I hope you get an idea what kind of business objects are required. We’ll be creating those objects in the next step. At this point, you can run the application once to make sure things don’t break. We will be adding code in the code-behind (MainPage.xaml.cs) later.

Create the WCF Service – Now lets go to the web project and add a new item. Right click on your Web application, Select Select a “Silverlight enabled WCF application” (I named the service LotrService.svc). Once you add this item, you will find a ServiceContract (the class or sometimes an interface) stub generated for you. We’ll be adding our own DataContract (additional classes) and we’ll create an OperationContract (functions) to serve the data. At this point you should know what’s 3-tier architecture. Specifically, you should know what’s a Business Object. In our application we will create a class that represents the Business Object and decorate it with the [DataContract] tag and that will be our data contract. We’ll also decorate each of our properties that need to be exposed with the [DataMember] tag. Read more about data contracts on MSDN @ http://msdn.microsoft.com/en-us/library/ms733127.aspx

Why do we need to add this Decoration? – We need to do this to let the application know that this Business Object is serializable.

Why do we need to serialize this Object? – Because that’s the only way we can send data from one system to another. (Web Services… Duh!)

Now the code below shows contains the code that goes in our Service (LotrService.svc.cs). Quite simple actually. Just pay attention to the ServiceContract, OperationContract, DataContract and DataMembers. (Without these, you’ll not be able to run the application successfully).

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class LotrService
{
    [OperationContract]
    public void DoWork()
    {
        // Add your operation implementation here
        return;
    }

    /// <summary>
    /// This service rewrites the LotrCharacter Object's name and returns the updated object
    /// </summary>
    /// <param name="lotrChar">An instance of the LotrCharacter</param>
    /// <returns>LotrCharacter</returns>
    [OperationContract]
    public LotrCharacter GetModifiedCharacter(LotrCharacter lotrChar)
    {
        try
        {
            lotrChar.Message = String.Format("Welcome, {0} - the {1} of {2}. ", lotrChar.Name, lotrChar.Group, lotrChar.Location);
            if (lotrChar.OwnsRing)
                lotrChar.Message += "Please go drop the ring off at Mordor. You can use my Metro Card!";
            else
                lotrChar.Message += "No Ring? Then lets be Merry with some Pipe Weed!";

            return lotrChar;
        }
        catch (Exception)
        {
            return null;
        }
    }
}

[DataContract]
public class LotrCharacter
{
    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public string Location { get; set; }

    [DataMember]
    public string Group { get; set; }

    [DataMember]
    public bool OwnsRing { get; set; }

    [DataMember]
    public string Message { get; set; }
}

Add the WCF Service Reference– Now its time to consume this service. Go to your Silverlight project (In my case SilverlightWcf) and right click on the ‘References‘ system folder. Select ‘Add Service Reference‘. This opens up a new form. Here click the ‘Discover’ button and you’ll find the services in your solution. Expand them, look at what’s inside. It’ll show the list of services available. Look around, play around and before you add the reference, give it a proper name (I named mine LotrServiceReference).

Sometimes you might get this error: The type ‘SilverlightWCF.Web.LotrService’, provided as the Service attribute value in the ServiceHost directive could not be found.

Or sometimes the service reference may not list the available services properly. This usually occurs when your program has not been built due to which your assemblies have not been loade. One simple way to fix this is to run your Web application that contains your WCF service by setting an ASPX page as the startup page. Running fine? Now just type in the URL of your service in the browser (doesn’t matter if you’re running it in VS {Cassini} or IIS. In my case the URL is http://localhost:53768/LotrService.svc). Check if the url opens up and the page looks like the screenshot below. If it does, you’re fine. Just go ahead and add the Service Reference in your Silverlight project again (or update the reference if it was already added).

Consume the Service – Now that we have the Service reference added successfully, lets add some code to the Silverlight Project. We’ll go back to MainPage.xaml.cs and here we’ll add a using statement to reference the classes in our Service Reference. Each service reference is wrapped in its own namespace whose name is same as the one you provided while adding (in my case is LotrServiceReference).

using SilverlightWCF.LotrServiceReference;

On the button click event handler, we’ll create a new instance of LotrCharacter and assign the values from the form. LotrCharacter is now available as we have added a service reference and the data contracts are also referenced. We will then pass the LotrCharacter object to the service, which will make certain modifications to the object, and then we’ll asynchronously fetch the modified LotrCharacter. The code for that is shown below. If you have any doubts on this, leave a comment below. (Also I’ll add a new post on binding the LotrCharacter object to the from. Statements like myCharacter.Name = TxtName.Text; are frowned upon. Check back soon.)

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void BtnSubmit_Click(object sender, RoutedEventArgs e)
    {
        // Store values from the form into our business object
        LotrCharacter myCharacter = new LotrCharacter();
        myCharacter.Name = TxtName.Text;
        myCharacter.Location = Convert.ToString(((ComboBoxItem)CmbLocation.SelectedItem).Content);

        if (RdbElf.IsChecked == true) myCharacter.Group = Convert.ToString(RdbElf.Content);
        else if (RdbHobbit.IsChecked == true) myCharacter.Group = Convert.ToString(RdbHobbit.Content);
        else if (RdbMen.IsChecked == true) myCharacter.Group = Convert.ToString(RdbMen.Content);

        myCharacter.OwnsRing = (ChkOwnRing.IsChecked == true);

        // This is the way we use the Client Object to call a function (Service) asynchronously
        // 1. Create a Client instance
        LotrServiceClient lotrSvc = new LotrServiceClient();
        // 2. Assign a ServiceCompleted Event Handler (As its Asynchronous)
        lotrSvc.GetModifiedCharacterCompleted +=
            new EventHandler<GetModifiedCharacterCompletedEventArgs>(LotrSvc_GetModifiedCharacterCompleted);
        // 3. Call the Service (Asynchronously)
        lotrSvc.GetModifiedCharacterAsync(myCharacter);
    }

    protected void LotrSvc_GetModifiedCharacterCompleted(object senderm, GetModifiedCharacterCompletedEventArgs e)
    {
        // Its a good practice to check for errors after receiving a response
        if (e.Error != null)
        {
            TxtMessage.Text = e.Error.Message;
            TxtMessage.Foreground = new SolidColorBrush(Colors.Red);
            return;
        }

        // e.Result will always have the return value of the service (In case of Async functions)
        LotrCharacter c = e.Result as LotrCharacter;
        TxtMessage.Text = c.Message;
    }
}

And that’s it! Run the application. The above code sample is with Silverlight 4 and Vs 2010. This code should be pretty much the same with Silverlight 3 and vs 2008. Let me know if you are having any trouble running this.

A little bit on asynchronous events – While you’re using WCF services, you’ll be creating event handlers all the time. In .net all event handlers must have 2 arguments to be valid. 1 – the object that’s sending the event and 2 – the event argument. When you add a service reference, for each service, VS creates 3 objects that you’ll be using –

  1. The Async Function (GetModifiedCharacterAsync in this case)
  2. The Event Delegate (GetModifiedCharacterCompleted in this case)
  3. The Event Completed Argument (GetModifiedCharacterCompletedEventArgs in this case)

Using these three you’ll be creating an event handler and assigning this handler to the event delegate using the += operator. To use async functions you should know “What should be done once you get the data”. Identify these steps and put those in the event handler. These statements are executed automatically (asynchronously) when ‘CompletedEvent’ occurs. For people coming from a background of normal ADO.NET like data retrieval, this is where you’ll find a big difference.