Create new account I forgot my password    

Silverlight and WCF Deployment Gotcha
Rating: 3 user(s) have rated this article Average rating: 4.7
Posted by: Malcolm Sheridan, on 7/20/2009, in category "Silverlight 2, 3 and 4"
Views: this article has been read 11298 times
Abstract: The following article demonstrates how to overcome deployment issues when using Silverlight and WCF websites.

Silverlight and WCF Deployment Gotcha
 
Silverlight has been around for over a year now and it’s a great technology. One gotcha that I ran into after deploying my web application was any calls from the Silverlight application to a local WCF service stopped working. I tested it locally before deploying and everything worked. I quickly realised that the endpoint address in the ServiceReferences.ClientConfig configuration file was pointing to my development server, not the production server. This file is compiled into the .xap file that is deployed to your web server, so instead of changing the endpoint address before you deploy, I’ll show you a simple trick that allows your application to work in development, test and production environments with a two lines of code. This is achieved by using the System.Uri class.   By using this class you can tell your Silverlight application to point to a specific endpoint address instead of what’s defined in the ServiceReferences.ClientConfig file.
To begin with open Visual Studio 2008 and choose File > New > Project > Silverlight > Silverlight Application. Once that is done we need to create a Silverlight enabled WCF service. Right click the project and choose Add > New Item > Silverlight > Silverlight-enabled WCF service:
SilverlightApplication1
Name this service Person.svc. Once the file has been added to the project, add the following code:
C#
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Person
{
[OperationContract]
      public string GetSurname()
      {
            return "Sheridan";
}
}
 
VB.NET
<ServiceContract(Namespace := ""), AspNetCompatibilityRequirements(RequirementsMode := AspNetCompatibilityRequirementsMode.Allowed)> _
Public Class Person
<OperationContract> _
Public Function GetSurname() As String
             Return "Sheridan"
End Function
End Class
 
I have defined one public method called GetSurname which returns a string. I’m keeping this service as simple as possible for this example. Build your project before moving on.
Next open the Silverlight project. Add a reference to the WCF service we just created. Right click on the Silverlight project and choose Add Service Reference. The service reference dialog will appear. Click the Discover button and Visual Studio will automatically locate WCF services in the solution.
AddServiceReference
Now that we have the reference, we can turn our attention to the MainPage.xaml file. Add the following xaml:
<Grid x:Name="LayoutRoot">
    <StackPanel Orientation="Horizontal">
            <Button x:Name="btnGetSurname" Width="100" Height="25" Content="Go" Click="btnGetSurname_Click" />
            <TextBox x:Name="txtSurname" Width="100" Height="25" />
    </StackPanel>
 </Grid>
Now it’s time to add code to the Button click event to call the service. Normally you would code the application like the following to call the WCF service:
C#
PersonRef.PersonClient client = new PersonRef.PersonClient();
client.GetSurnameCompleted += delegate(object s, PersonRef.GetSurnameCompletedEventArgs args)
{
txtSurname.Text = args.Result;
};
client.GetSurnameAsync();
 
VB.NET
Dim client As New PersonRef.PersonClient()
AddHandler client.GetSurnameCompleted, Function(s, args) AnonymousMethod1(s, args)
client.GetSurnameAsync()
 
Private Function AnonymousMethod1(ByVal s As Object, ByVal args As PersonRef.GetSurnameCompletedEventArgs) As Boolean
txtSurname.Text = args.Result
      Return True
End Function
 
In the code above the code will call the WCF service and return the value. For this code to run, the application uses the ServiceReferences.ClientConfig configuration file and grabs the endpoint address value for the WCF service. On my machine the endpoint address is the following:
<client>
<endpoint address=http://localhost:4192/Person.svc binding="customBinding"
binding Configuration="CustomBinding_Person" contract="PersonRef.Person"
      name="CustomBinding_Person" />
</client>
As you can see from code above, the application will connect to http://localhost:4192/Person.svc. If you run the project locally it works. But what happens when you deploy this to a separate web server? Your code will fail because the endpoint address is pointing to your local machine. One workaround that I found good is to use the System.Uri class in your code to point to a WCF service that is relative to the website. To make this work replace the code previously added with the following:
C#
Uri uri = new Uri(Application.Current.Host.Source, "../Person.svc");
PersonRef.PersonClient client = new PersonRef.PersonClient("CustomBinding_Person", uri.AbsoluteUri);           
client.GetSurnameCompleted += delegate(object s, PersonRef.GetSurnameCompletedEventArgs args)
{
txtSurname.Text = args.Result;
};
client.GetSurnameAsync();
 
VB.NET
Dim uri As New Uri(Application.Current.Host.Source, "../Person.svc")
Dim client As New PersonRef.PersonClient("CustomBinding_Person", uri.AbsoluteUri)
AddHandler client.GetSurnameCompleted, Function(s, args) AnonymousMethod1(s, args)
client.GetSurnameAsync()
 
Private Function AnonymousMethod1(ByVal s As Object, ByVal args As PersonRef.GetSurnameCompletedEventArgs) As Boolean
txtSurname.Text = args.Result
      Return True
End Function
In the code above I have created an Uri object which points to the Person WCF service in the web application. Since the code is being executed from the xap file, the URI is relative to the website. On the next line, the endpoint configuration name is used, CustomBinding_Person, and the remote address value is the uri.AbsoluteUri value
C#

Uri uri = new Uri(Application.Current.Host.Source, "../Person.svc");
PersonRef.PersonClient client = new PersonRef.PersonClient("CustomBinding_Person", uri.AbsoluteUri);  
 
VB.NET

Dim uri As New Uri(Application.Current.Host.Source, "../Person.svc")
Dim client As New PersonRef.PersonClient("CustomBinding_Person", uri.AbsoluteUri)
 

If you build this application, it can now be run locally or on a dedicated web server and the code will work without having to update the configuration file. Perfect!

The entire source code of this article can be downloaded over here










Page copy protected against web site content infringement by Copyscape


How would you rate this article?

User Feedback
Comment posted by Gopi on Monday, July 20, 2009 1:01 PM
Hi,
Thanx for the article.
i have one question.
Where are your hosting the created wcf service? in IIS or some where else?
I have created a WCF service and hosted it in IIS in a system 'A' and now i am accessing this service from another machine 'B' by adding service ref  as http://A/serive.svc. Well as of now it didn't it dint give me any trouble but is this the safe to do like this?
Comment posted by Malcolm Sheridan on Monday, July 20, 2009 8:58 PM
@Gopi
The service was being hosted in IIS.  This article explains about referencing a WCF service in the same solution, so when you deploy, you're not referencing the WCF service via the config file.
Comment posted by Soctt Jason on Wednesday, July 22, 2009 5:37 PM
thank you. this is excatly what I was looking for.  Solve my majoy problem.  but i have a small question, why "../" in "../Person.svc"?  thank you again.
Comment posted by Malcolm Sheridan on Wednesday, July 22, 2009 7:28 PM
@Scott
The reason for that is because the code is run from the xap file, which is located in the ClientBin folder of the website.  
Comment posted by Nitin on Thursday, September 24, 2009 6:14 PM
thank you so much. it solved my issue
Comment posted by Greg on Tuesday, November 17, 2009 7:25 PM
I have implemented for my application because I was having the same issue and now, when I try to run it on my development machine, I get the following error:

System.ArgumentException was unhandled by user code
  Message="The provided URI scheme 'file' is invalid; expected 'http'.\r\nParameter name: via"
  StackTrace:
       at System.ServiceModel.Channels.TransportChannelFactory`1.ValidateScheme(Uri via)...

This gets thrown when I attempt to instiate my WCF service client, with the following signature:
    Uri uri = new Uri(Application.Current.Host.Source, "../WebServices/MyWCFService.svc");
                    _myServiceClient = new MyServiceClient("BasicHttpBinding_MyWCFService", uri.AbsoluteUri);
                
If I examine the client parameter being passed to the ClientServiceChannel constructor I see that its endpoint is "file:///C:/Users/Me/Documents/MyProjects/MySolution/MyApp/Bin/WebServices/MyWCFService.svc" (folder and filenames changed for privacy).

I'm obviously missing something. Any ideas?
Comment posted by Sumit on Monday, August 16, 2010 3:32 AM
Nice 'hack' if I may dare to say so. But thanks for putting it up. I've been looking high and low for such a solution.

Root of the problem, changing configuration information before deploying to different environment is really self-defeating the whole 'configuration file' concept. In this case, I guess the argument is - 'because silverlight's xap file is a executed on client side, it must know the service location before download and hence the webservice binding must happen at build time!!!!' but still if I have a configuration I expect to update it and 'things' dependent on the configuration (like webservice references) should pick them up on change!!!

Anyway, enough of ranting, thanks for the solution again!!!

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel

NEWSLETTER