When you add a WCF service reference to a Silverlight Application, it generates the ServiceReference.ClientConfig file where the URL of the WCF endpoint is defined. When you add the WCF service reference on a development computer, the endpoint URL is on localhost. But when you deploy the Silverlight client and the WCF service on a production server, the endpoint URL no longer is on localhost instead on some domain. As a result, the Silverlight application fails to call the WCF services. You have to manually change the endpoint URL on the Silverlight config file to match the production URL before deploying live. Now if you are deploying the Silverlight application and the server side WCF service as a distributable application where customer install the service themselves on their own domain then you don’t know what will be the production URL. As a result, you can’t rely on the ServiceReference.ClientConfig. You have to dynamically find out on which domain the Silverlight application is running and what will be the endpoint URL of the WCF service. Here I will show you an approach to dynamically decide the endpoint URL.
First you add a typical service reference and generate a ServiceReference.ClientConfig that looks like this:
<configuration> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_ProxyService" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <security mode="None" /> </binding> <binding name="BasicHttpBinding_WidgetService" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <security mode="None" /> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="http://localhost:8000/Dropthings/API/Proxy.svc/pox" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ProxyService" contract="DropthingsProxy.ProxyService" name="BasicHttpBinding_ProxyService" /> <endpoint address="http://localhost:8000/Dropthings/API/Widget.svc/pox" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_WidgetService" contract="DropthingsWidgetService.WidgetService" name="BasicHttpBinding_WidgetService" /> </client> </system.serviceModel> </configuration>
As you see, all the URL are pointing to localhost, on my development environment. The Silverlight application now need to dynamically decide what URL the Silverlight app is running from and then resolve the endpoint URL dynamically.
I do this by creating a helper class that checks the URL of the Silverlight application and then decides what’s going to be the URL of the endpoint.
public class DynamicEndpointHelper { // Put the development server site URL including the trailing slash // This should be same as what's set in the Dropthings web project's // properties as the URL of the site in development server private const string BaseUrl = "http://localhost:8000/Dropthings/"; public static string ResolveEndpointUrl(string endpointUrl, string xapPath) { string baseUrl = xapPath.Substring(0, xapPath.IndexOf("ClientBin")); string relativeEndpointUrl = endpointUrl.Substring(BaseUrl.Length); string dynamicEndpointUrl = baseUrl + relativeEndpointUrl; return dynamicEndpointUrl; } }
In the Silverlight app, I construct the Service Client this way:
private DropthingsProxy.ProxyServiceClient GetProxyService() { DropthingsProxy.ProxyServiceClient service = new DropthingsProxy.ProxyServiceClient(); service.Endpoint.Address = new EndpointAddress( DynamicEndpointHelper.ResolveEndpointUrl(service.Endpoint.Address.Uri.ToString(), App.Current.Host.Source.ToString())); return service; }
After creating the service client with default setting, it changes the endpoint URL to the currently running website’s URL. This solution works when the WCF services are exposed from the same web application. If you have the WCF services hosted on a different domain and you are making cross domain calls to the WCF service then this will not work. In that case, you will have to find out what’s the domain of the WCF service and then use that instead of localhost.
You could pass the service URL through the InitParams property on the Silverlight object. You could get even fancier and dynamically set the InitParams in the code behind. Now you can use a get the URL from the web.config or from a configuration service. You would then create you clinet proxy as you did above.