Deploying Silverlight with WCF Services

February 1, 2011 6 Comments

So I know that this topic is nothing new, however, this is still one of the most common deployment issues that people ask me about.  That being the case, I decided to add a post on the topic to demonstrate my approach.

I love the work the Silverlight team has put in to generating client stubs for web services.  It was not that long ago that I was having to write out all of those stubs and I’m glad to be done with it. However, there is one piece of the puzzle that seams to be missing from the solution: smooth deployment of the Silverlight application and the WCF services.

 

Setting up Our Project

To get started on the topic, let’s begin by setting up a project so we can look at what is going on under the hood.

Start by creating a new “Siverlight Application” in Visual Studio 2010.  When creating the project, make sure you have the following two options set: “Host the Silverlight applcation in a new Web site” and do not check the “Enable WCF RIA Services”.

image

We are not enabling RIA on this project simply to keep the solution clean and focus our WCF services.

Once your project is created, add a new “Siverlight-enabled WCF Service” (I called mine MyService.svc) to our Web project.

image

If you open up the new service, you will find there is a sample “DoWork” method already created for you to demonstrate how to set up methods in your service.  For our purposes, we are just going to modify that method a bit to return a string.

[OperationContract]
public string DoWork()
{
    // Add your operation implementation here
    return "Hello from My WCF Service";
}

I know, nothing too terribly exciting, but it will work for our purposes.

Reminder: Anytime you add a new service to your web project or make a modification to the structure of it (ie add/change the method signatures), you need to recompile the web project prior to adding/changing the service in the Silverlight application.

Once we compile our Web project, we can move on to adding our new WCF service to the Silverlight application.  To do that, right-click on the Silverlight Project and select “Add Service Reference”.  Once the service dialog box comes up, click the “Discover” button and you should see your service in the list.

image

 

After giving your service a namespace and selecting “OK”, there are several things that get added to your project.  Most of the items can be found if you expand the service reference that was added to your project.  In addition, you will notice a “ServiceReferences.ClientConfig” file added to your project.  Don’t forget about this file, because we will be coming back to this file in a minute.

The last thing that we need to add to our project, to make it test worthy, is some sort of interaction with our service.  If you remember, our service simply returns a string.  So, our nice and complicated UI is going to consist of a TextBlock:

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock x:Name="txtMsg" 
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"/>
    </Grid>

 

Thanks to all of the plumbing that is done for us, it is a rather straight forward process to call our new service in code. 

    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            MyServiceClient client = new MyServiceClient();

            client.DoWorkCompleted += 
                new EventHandler<DoWorkCompletedEventArgs>
                                (client_DoWorkCompleted);
            client.DoWorkAsync();
        }

        void client_DoWorkCompleted(object sender, 
                                    DoWorkCompletedEventArgs e)
        {
            txtMsg.Text = e.Result;
          
        }

    }

This code simply creates a client to our service and calls our one method.  Once the service returns, we are simply displaying the results in our TextBlock.

And that is that.  You should be able to compile and run your application and get back something like this:

image

 

Deploying the Project

Now that we have our new Silverlight application, we simply can’t wait to deploy it and show off our new Silverlight skills to all of our friends.  So you deploy the project to your IIS server, launch the site, and….. it breaks…

You have to love it when that happens…

So why won’t it deploy?  What could be so different between your IIS box and your development box? The answer lies in that “ServiceReferences.ClientConfig” file.  Yep, the same one I told you we would come back to in a minute.

Let’s have a look at it real quick:

<configuration>
    <system.serviceModel>
        <bindings>
            <customBinding>
                <binding name="MyServiceCustom">
                    <binaryMessageEncoding />
                    <httpTransport maxReceivedMessageSize="2147483647" 
                                   maxBufferSize="2147483647" />
                </binding>
            </customBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:40228/MyService.svc" 
                      binding="customBinding"
                      bindingConfiguration="MyServiceCustom" 
                      contract="MyService.MyService"
                name="MyServiceCustom" />
        </client>
    </system.serviceModel>
</configuration>

The culprit is the endpoint address.  When you create a service client, it defaults to the address that is listed here (which, more than likely, is not the same location that you deployed it to).  Any time that you create a service client in your code, using the default constructor, this is the location that it assumes the service is at.

So now we know where the problem lies, how do we fix it?

 

The Solution…

Now the first temptation is to simply update the address to point to the appropriate location.  While this will fix your problem, it’s really not the cleanest approach.  The first issue you run into, is you will need to remember to change it between the development and the production versions.  In addition, any time the url changes to your application (whether you move it, rename the site, etc), you will have to go in and update this location.  The first and only time I went this route, it bit me several times.

A more forgiving approach is to look at the constructor of our service client.  Instead of using the default constructor, which uses the default location, we are going to dynamically assign our service location.

[Note: in addition to assigning the location of the service, you can also set all of the endpoint and binding information that is defined in our ClientConfig]

There are a couple of different approaches you can take here.  However, most of the information in our ClientConfig I don’t want to have to change or assign in code.  So I simply want to update the address of our service and use the rest of the defaults that are assigned in the ClientConfig.

Before we can do that, there is one piece of information that we need to add to our web service in the web.config.

We need to add a name to the endpoint of our service on the server.  This will allow us to reference the correct endpoint.  Here is what you will need to add:

image

Once you have done that, then head back over the our MainPage.xaml.cs, where we called our service client.  Instead of using the default constructor, we are going to use the following:

   Uri servUri = new Uri("../MyService.svc", UriKind.Relative);
   EndpointAddress servAddr = new EndpointAddress(servUri);
   MyServiceClient client = new MyServiceClient("MyServiceCustom", 
                                                 servAddr );

The constructor that we used for the client has two properties.  The first is the endPointConfigurationName, which is what we added to our endpoint in the web.config.

The second is the location to our service, which is defined as an EndpointAddress.

[Note: The Application.Current.Host.Source returns the Uri of our .xap file on the web server (which by default is the ClientBin folder).  So you need to make sure your path is relative to that location.

So what does this give us? By creating your service client this way, your Silverlight application will be able to find your WCF service no matter where you application is deployed.  It is important to note, that this is assuming that your web project is being deployed as is and that the WCF services are going to be in the same relative location to your .xap file.

There are a couple of other variations on this.  However, I’ve found that this works in every scenario that I’ve come across.

I hope this helps to ease the deployment pains some people are running across.  Please feel free to contact me if you run into any issues or questions.

If you want to get a copy of the project for this post your can download it here.

Filed in: Silverlight • Tags: , ,

Comments (6)

Trackback URL | Comments RSS Feed

Sites That Link to this Post

  1. Deploying Silverlight with WCF Services | www.nalli.net | February 2, 2011
  1. Nice article and a frequently asked question in the Silverlight forums.

    Btw. you can also use the relative URL feature (I think this is new in Silverlight 4):

    Uri servUri = new Uri(“../MyService.svc”, UriKind.Relative);

  2. Tony Champion says:

    You would think as many Uri’s as I write I would have noticed that before. That’s what happens when you get use to reusing a chunk of code. That’s a cleaner solution, so I’ll get it fixed. Thanks…

  3. geedubb says:

    A good post, thanks.

    Another thing that I tend to do is use Silverlight’s InitParams to pass in the host name so that an absolute path can be specified in the constructor for the WCF proxy (useful if your WCF resides on a different domain).

  4. wxp says:

    That’s a wonderful solution! Thank you so much!!!!

  5. Matt Paulson says:

    Very nice solution… I was struggling a bit and found that I forgot to rerfesh the Service on the client and it was not picking up the web configs name change… So it is worth noting to make sure you rebuild both projects and and refresh your Service and the rebuild again and then try it…

Leave a Reply