Click here to Skip to main content
15,888,454 members
Articles / Programming Languages / C#

Deploying Silverlight with WCF Services

Rate me:
Please Sign up or sign in to vote.
4.25/5 (4 votes)
1 Feb 2011CPOL6 min read 28.8K   5   6
Deploying Silverlight with WCF Services

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 “Silverlight Application” in Visual Studio 2010. When creating the project, make sure you have the following two options set: “Host the Silverlight application 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 “Silverlight-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.

C#
[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 (i.e. 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:

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

C#
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:

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

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
President Champion DS
United States United States
Tony Champion is a software architect with over 16 years of experience developing with Microsoft technologies. As the president of Champion DS and its lead software architect, he remains active in the latest trends and technologies, creating custom solutions on Microsoft platforms. Tony is an active participant in the community as a Microsoft MVP, international speaker, published author, and blogger. He focuses on a wide range of technologies from web solutions such as HTML5, JavaScript, Silverlight to client platforms for Windows Phone and Windows 8. He can be found on his blog at tonychampion.net and on twitter at @tonychampion.

Comments and Discussions

 
Questionhello ,please help me Pin
stelios198430-Sep-14 22:11
stelios198430-Sep-14 22:11 
QuestionSame error even after changes are done. Pin
Sunilappu28-May-12 21:08
Sunilappu28-May-12 21:08 
GeneralFollowed your example step by step Pin
code_junkie7-Feb-11 4:44
code_junkie7-Feb-11 4:44 
and it failed to compile. Sorry I am pretty new to SL.

"The type or namespace name 'DoWorkCompletedEventArgs' could not be found (are you missing a using directive or an assembly reference?)"

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

I'm not sure how to fix it...

This happens before I get to the "Deploy" section.
GeneralRe: Followed your example step by step Pin
Tony Champion (Champion DS)8-Feb-11 17:14
professionalTony Champion (Champion DS)8-Feb-11 17:14 
GeneralWell done. Pin
louiso997-Feb-11 3:44
louiso997-Feb-11 3:44 
GeneralNice article, nice tutorial Pin
Lee N Middleton3-Feb-11 10:46
Lee N Middleton3-Feb-11 10:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.