×

First time here?

You are looking at the most recent posts. You may also want to check out older archives. Please leave a comment, ask a question and consider subscribing to the latest posts via RSS or email. Thank you for visiting!

You’ve written your service.  You’ve written your Silverlight application.  You Add Service Reference to your application and got the client proxy code.  Your app ‘works on your machine’ and you push it out. 

FAIL.

NotFound.

Crap.  You forgot that your service reference had your local URI endpoint in there and when you moved it to staging and/or production it failed.  You start cursing Microsoft and the Silverlight team and add to the threads in the forums or perhaps initiate a new wishlist item for the team and throw it out on Twitter and encourage votes.

It seems this is still a common frustration and people are trying to solve it in different ways.  I’m going to throw out what is my preferred mechanism and add some additional tips and tricks here that hopefully some are using.

The Setup

Here’s the setup.  You have a Silverlight application and a web service.  To keep it simple I started with File…New Silverlight Application – kept the web project there. I added a Silverlight-enabled WCF Service to my web project with this following code:

   1: [OperationContract]
   2: public string SayHello()
   3: {
   4:     // Add your operation implementation here
   5:     return "Hello World [DEVELOPMENT]";
   6: }

I then added 2 more empty ASP.NET Web Application projects to my solution, added a single Silverlight-enabled WCF Service to each one of them with the identical code, changing only the return string to PRODUCTION or STAGING to differentiate the response.  I called one project ProductionService and the other StagingService to simulate a production and staging environment.  I then added (because it wouldn’t work otherwise in my test setup) a clientaccesspolicy.xml file to the production/staging service projects.

NOTE: You may not have to do this clientaccesspolicy.xml setup.  This was only because I deployed the Silverlight app only to one web project, not others.  This may not be required for you.  See step below on Silverlight App in Same Web Project as Service section on why.

I’ve added some rudimentary XAML to the app to basically show the current default service that will be used (with the option to change it) and the response code:

Sample application snapshot

Now to explain what I’ve done/recommend.

The ServiceReferences.clientconfig ‘magic’

When you add a service reference via the Add Service References option in Visual Studio, you get a new file in your Silverlight application called ServiceReferences.clientconfig.  This contains the binding and endpoint configurations for the service you just referenced.  Here’s where you can change some things up.

By default it adds the configuration for the literal endpoint you just referenced (think absolute URI here…most of the time in development this may be localhost).  The file isn’t fixed though and you can add your other configurations there as well.  Here’s my initial updated config file with the addition of the production and staging URI endpoints.

   1: <configuration>
   2:     <system.serviceModel>
   3:         <bindings>
   4:             <customBinding>
   5:                 <binding name="CustomBinding_HelloWorldService">
   6:                     <binaryMessageEncoding />
   7:                     <httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
   8:                 </binding>
   9:                 <binding name="StagingServiceBinding">
  10:                     <binaryMessageEncoding />
  11:                     <httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
  12:                 </binding>
  13:                 <binding name="ProductionServiceBinding">
  14:                     <binaryMessageEncoding />
  15:                     <httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
  16:                 </binding>
  17:             </customBinding>
  18:         </bindings>
  19:         <client>
  20:             <endpoint address="http://localhost:40473/HelloWorldService.svc"
  21:                 binding="customBinding" bindingConfiguration="CustomBinding_HelloWorldService"
  22:                 contract="HelloServices.HelloWorldService" name="CustomBinding_HelloWorldService" />
  23:             <endpoint address="http://localhost:40848/HelloWorldService.svc"
  24:                 binding="customBinding" bindingConfiguration="StagingServiceBinding"
  25:                 contract="HelloServices.HelloWorldService" name="StagingServiceBinding" />
  26:             <endpoint address="http://localhost:40849/HelloWorldService.svc"
  27:                 binding="customBinding" bindingConfiguration="ProductionServiceBinding"
  28:                 contract="HelloServices.HelloWorldService" name="ProductionServiceBinding" />
  29:         </client>
  30:     </system.serviceModel>
  31: </configuration>

Notice the endpoint names: CustomBinding_HelloWorldService, StagingServiceBinding, ProductionServiceBinding.  The first was created for me by VS – hence the awesome hugely unhelpful name :-).  By default, if you added this code in your Silverlight application:

   1: HelloWorldServiceClient client = new HelloWorldServiceClient();

Then it will be using the default endpoint it creates (which would only be one of them unless you add custom ones like I did above).

Initializing the Service with different endpoints

Now that you know that the client config file can have multiple configuration endpoints, how would you use them?  Simple.  If you take a look at the proxy code that gets generated for you when you Add Service Reference (this is in the Reference.cs file when you use the ‘show all files’ option in VS) you’ll notice that the constructor for HelloWorldService is overloaded to allow and endpoint configuration, or optionally explicit binding/endpoint address information.  It’s the former that will make this easier for you.

Take our above ServiceReferences.clientconfig modifictation.  Let’s say we wanted to work with the staging service, we could now simply instantiate with:

   1: HelloWorldServiceClient client = new HelloWorldServiceClient("StagingServiceBinding");

In fact, I might argue that you should never use the default constructor.  Being more explicit leads to easier code to read/track in my opinion.  You don’t expect to be on this project for the rest of your life do you?  I didn’t think so…make it easier on the next developer that has to come behind you and fix your bugs enhance the code to add functionality and be explicit.

Being Dynamic about your Endpoint Initialization

Obviously you don’t want to hard-code various endpoint names in your instantiation of the service proxies.  In fact, you may be struggling because you may push your code out via automated build servers and you don’t want to have to build the XAP, then change something, blah blah.  This is where conditional compilation can help.  For instance, here’s how I have the code in this project:

   1: string _endpointName = "RelativeBinding";
   2:  
   3: #if PRODUCTION
   4:     _endpointName = "ProductionServiceBinding";
   5: #endif
   6:  
   7: #if STAGING
   8:     _endpointName = "StagingServiceBinding";
   9: #endif
  10:  
  11: HelloWorldServiceClient client = new HelloWorldServiceClient(_endpointName);

Now I just have to make sure that my compile tasks add those conditional flags.  This is relatively simple.  You could use Visual Studio’s Configuration Build Manager to create new profiles, or you could also customize an MSBuild task to append those constants.  It is simple and there are plenty of resources to help you here.  For my project I simply customized (added) new configuration profiles in Visual Studio and have been manually switching them to test.

Silverlight App in Same Web Project as Service

But wait, there’s more!

If you have a simpler solution where your service is being served up in the same web application/site as your Silverlight application, then you have a simpler solution using Silverlight 4.  Just to clarify, what I mean by this is that your app - let’s say http://foo.com/clientbin/myapp.xap is a part of the same web application http://foo.com which serves up the service you are calling http://foo.com/helloworldservice.svc. 

Good news for you if you are using Silverlight 4.  You can now use relative path information for service references!  Let’s say your XAP is in /ClientBin/MyApp.xap and your service is in the same root location as the ClientBin folder at /HelloWorldService.svc.  This means that “../HelloWorldService.svc” will work!  I’d recommend still being explicit in your code so that it helps those come behind you.  In my client config file I added a “RelativeBinding” configuration:

   1: <endpoint address="../HelloWorldService.svc"
   2:                 binding="customBinding" bindingConfiguration="RelativeBinding"
   3:                 contract="HelloServices.HelloWorldService" name="RelativeBinding" />

and then in my code I can initiate it like I’ve done above using the named configuration.  But notice in the configuration I used ../HelloWorldService.svc as the URI for the service endpoint.  Assuming my staging and production follow the same paths, I don’t have to worry about conditional compilation, etc. and can push these out in the various environments.

Code Specific Endpoints to hide your configurations

In theory if your solution can use the relative binding scenario described above there is not too much to worry about as far as revealing too much.  However if you are using the other method about adding multiple configurations to your ServiceReferences.clientconfig file you should be aware that this file is compiled as a resource and could show others your staging/dev URIs that you may not want.  This might be a subtle by-product of getting added benefit to making the process easier though but you should be aware of these capabilities since tools like Silverlight Spy and Reflector could enable someone to look at your resource files.

You could by pass the client config named endpoints mechanism and use conditional compilation with explicit code-created endpoints.  Using the conditional statements as shown above, only the code that meets the condition will be compiled into IL.  Thus decompilation doesn’t show the other #if options.  So in Reflector or other tools you’d only see what was output.  Given this you could be even more aboslutely explicit and do something like this:

   1: BasicHttpBinding binding = new BasicHttpBinding();
   2: EndpointAddress endpoint;
   3:  
   4: #if PRODUCTION
   5:     _endpointName = "ProductionServiceBinding";
   6:     endpoint = new EndpointAddress("http://myproductionserver.com/HelloWorldService.svc");
   7: #endif
   8:  
   9: #if STAGING
  10:     _endpointName = "StagingServiceBinding";
  11:     endpoint = new EndpointAddress("http://mySTAGING.com/HelloWorldService.svc");
  12: #endif
  13:  
  14: HelloWorldServiceClient client = new HelloWorldServiceClient(binding, endpoint);

Using this conditional compilation method you’re doing a bit more ‘hard-coding’ than relying on changing configuration and not code, but it might be more suitable to your liking.  Sure, this can still be decompiled, but it would only reveal the endpoint you already will be using (which anyone could see anyway just watching HTTP traffic).

Summary

Managing your endpoints doesn’t have to be difficult.  Hopefully these simple ways give you an idea of the options you can use.  Can we do better in helping manage this easier?  I think so.  And I know we’re thinking about it as well.

You can download my complete code sample for this application here: ManagingServiceEndpoints.zip.

Hope this helps!  (oh and hat-tip to Shawn who wrote about this for SL2…I’ve just expanded on the same idea going deeper and providing some updates for Silverlight 4)


This work is licensed under a Creative Commons Attribution By license.


4/5/2010 11:08 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Does not say anything about why links are blocked in Facebook.
4/5/2010 11:19 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Michael -- huh?! Why does facebook have anything to do with my above post?
4/5/2010 12:02 PM | # re: Managing service references and endpoint configurations for Silverlight applications
Josh -- I totally agree we could do better tooling here similar to ASPNET...we know that and are working on looking at solutions.

But I'm confused that if your infrastructure team uses powershell/msbuild to do configuration changes, isn't that the same risk as a recompile essentially...you could easily just as much regress (perhaps even worse) if those steps fail or incorrectly break the XAP.

But regardless, MSBuild is likely the *best* option here IMO...using custom tasks that merge .stage.config files in the right places. It isn't pretty, but it is the closest to the ASPNET solution we have with adding some manual capabilties.

It's fair to say none of these are all suggestions and no one soltuion will EVER work for everyone. For the most part, I get inquiries MOST of the time for the simpler scenarios...in that case the relative binding solution for those users will be ideal.
4/5/2010 12:06 PM | # re: Managing service references and endpoint configurations for Silverlight applications
I use WCF with SL quite a bit and this used to drive me crazy. I ended up building a simple helper class which dynamically sets the endpoint based on the Silverlight URL. This works fine for my needs for SL/WCF but having a more generic approach that works with other calling types (WPF, etc) would be nice...

public static MyServiceClient GetMyServiceClientProxy()
{
string fullPath = Application.Current.Host.Source.AbsolutePath;
string relativePath = "";
int pos = fullPath.IndexOf("/ClientBin");
if (pos != 0)
relativePath = fullPath.Substring(0, pos);

string hostname = "http://" + Application.Current.Host.Source.Host + ":" + Application.Current.Host.Source.Port + relativePath + "/Services/MyService.svc";
if (Application.Current.Host.Source.Port == 80)
hostname = "http://" + Application.Current.Host.Source.Host + relativePath + "/Services/MyService.svc";

return new MyServiceClient("CustomBinding_MyService", new EndpointAddress(hostname));
}
4/5/2010 4:34 PM | # re: Managing service references and endpoint configurations for Silverlight applications
I agree with the other Mark. I also made a helper class that the App initializes like:

ServiceProxy.ServiceUri := new Uri( App.Current.Host.Source, '../Service.svc' );

The other Mark's comment looks more complete. But I don't like the conditional build mechanism either. This technique works not matter how the app was compiled.
4/5/2010 5:25 PM | # re: Managing service references and endpoint configurations for Silverlight applications
Mark/Another Mark -- this assumes the Service is in the same location as the XAP (same web site) -- if this is true you don't even need your helper classes anymore for SL4 -- that's the reference to what I'm calling the 'relative binding' endpoint above.
4/5/2010 9:17 PM | # re: Managing service references and endpoint configurations for Silverlight applications
We are building a Silverlight application that the client will deploy to multiple locations worldwide. Currently, we are using initialization parameters to pass configuration service URI to SL application, which works, but I still consider it being a hack. With the SL4 relative binding things got easier, if relative location of the configuration service is consistent across deployments.
Another thing to consider is that by default certain browsers allow downloading only two files at a time, and WCF communication falls into this limitation. Therefore, you also have to consider a way to block other web service calls until configuration is loaded.
Another mechanism that we use is embedding configuration XML into the HTML host page and save the configuration into isolated storage for future use with OOB (Out-of-browser). It is not very secure, but works well in most scenarios.
I support Josh 100%. Indeed, we need Silverlight application configuration mechanism for SL applications that shall work in OOB scenarios as well.
4/6/2010 8:20 AM | # re: Managing service references and endpoint configurations for Silverlight applications
With the SL4 solution:

Can we use ~ instead of a relative path?

Does this work in dev where you may have multiple instances of Cassini running on different ports?

We currently do this:

public static EndpointAddress ConvertToSourceHostAddress(EndpointAddress existingAddress)
{
{
#if DEBUG
return existingAddress;
#endif

int port = Application.Current.Host.Source.Port;
string formattedPort = string.Empty;

if (port > 0 && port != 80)
formattedPort = string.Format(":{0}", port);

string newURI = string.Format("{0}://{1}{2}{3}",
existingAddress.Uri.Scheme,
Application.Current.Host.Source.Host,
formattedPort,
existingAddress.Uri.LocalPath
);

EndpointAddress newAddress = new EndpointAddress(newURI);
return newAddress;
}
}


4/6/2010 8:35 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Tim...thanks a log. Great material.

--t
4/6/2010 9:07 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Luddite -- yes, this multiple binding is more of an issue with WCF/.NET3.5. You'll be happy to know that this has changed in .NET4 :-). Your syntax at first glance looks correct to me.

Kelly/Josh -- noted. Would the approach that ASPNET uses be preferred?

JasonBSteele -- I don't think that would work. ~ is a character interpreted on server side. You can use relative paths for the XAP knowing that "/" is the root of the XAP *not* the web application.
4/6/2010 10:12 AM | # re: Managing service references and endpoint configurations for Silverlight applications
very helpful suggessions
4/7/2010 2:48 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Editing any wcf, service, web config file on .Net is a worse experience, i heard 2010 give intellisense, i hope we can have nice gui, which explanation of each binding, create custom binding bla2, debug/release end point also nice....
4/7/2010 8:56 AM | # re: Managing service references and endpoint configurations for Silverlight applications
I've been using a pattern for multiple environments for years that my clients have simply LOVED.

There are a number of ways to implement it, but the basic idea is this:

You add all of the machine names or prefixes or ip blocks as keys to that environment code (DEV, INT, QA, PROD)
<add key="myMachineName" value="DEV"/>

Then you have keys for actual settings:

<add key="MasterDB,DEV" value=""/>
<add key="LoggingDB,DEV" value=""/>
<add key="SLServiceAddress,DEV" value=""/>

This pattern allows you to identify all of your environments in one web.config.

Then, in code, you write an extension method that uses the machine name to determine the environment and using the passed setting key, it retrieves (and caches) the value:

string getSetting(keyName) {
string environment =
ConfigurationManager.AppSettings[System.Environment.MachineName];
return ConfigurationManager[String.Concat(keyName,",",environment];
}

David C.
8/11/2010 4:09 PM | # re: Managing service references and endpoint configurations for Silverlight applications
Thanks a lot for the useful thoughts about how to manage these references. We are trying to use the relative service reference you mention since our project co-hosts the XAP and the WCF Service.

However, msbuild & VS2010 are both inserting into ServiceReferences.ClientConfig a binding to localhost in addition to the relative binding. When deployed the application chooses localhost first, so we still have the same issue.

How can we control the generation of .ClientConfig so that the localhost binding is not generated?

Thanks!
8/23/2010 9:14 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Tim, great article.

I have a similar challenge except when my Silverlight app goes into production I never know initially what the name of the hosting server will be for the WCF service. This app is being deployed on private networks with multiple servers and one of the requirements prevented the SL app from being installed/residing on the same server as the WCF service. I wanted to get your opinion on the current approach I am using.

Within the application the WCF server address is passed via JSON to the silverlight app. This address is stored in the sites web.config file which is passed via initParm to the silverlight app. SL then assigns this as a variable that could be used in the query.

here are few snippets as to the example:

//pick up the JSON string and deserialize
string odsIn = GetParam("ODSIn").Replace("$", ",");
if (odsIn != "")
{
ODSInData = JsonHelper.DeserializeToObject<VisionAIR.DSW.Contracts.ODSIn>(odsIn);
}


//Gets a parameter passed to the Silverlight object that has the supplied name

public string GetParam(string paramName)
{
if (App.Current.Resources[paramName] != null)
return App.Current.Resources[paramName].ToString();
else
return string.Empty;
}

//then assign endpoint address
dswconnection = GetParam("EndpointAddress");

Within our queries we then can "re-point the address being used"
private void Query1()
{
QueryClient qc = new QueryClient("BasicHttpBinding_IQuery");
qc.Endpoint.Address = new System.ServiceModel.EndpointAddress(dswconnection);
//continue with query....

While this does have few points of potential failure I was wondering in situations such as this were a silverlight app was being deployed if there may be a more efficient approach to setting WCF endpoints.


Thanks for any insight!
12/17/2010 5:27 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Hi Tim,

After making the change in client config (making the URI relative), I'm getting issues when updating my service reference. The full path keeps being re-created by visual studio...and I end up with 2 endpoints being defined within the <client> tag. What am I doing wrong?

Cheers
12/17/2010 7:18 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Ah, nevermind...I'm guessing you just keep both endpoints defined...the one being used when updating the service reference, and the other being used at runtime?
2/14/2011 5:58 PM | # re: Managing service references and endpoint configurations for Silverlight applications
I am currently using a workaround to this problem jumping onto the back of visual studios configuration states that might help a few people. It seems to work okay in my instance but if anyone can spot any issues with it please let me know.

Basically I start by setting up one resource file and one App page for each configuration. For example in production I would have a App.PRD.xaml and a Resources.PRD.xaml. Within the resources file I have a string resource containing the address of the endpoint - additional environment information including image urls, binding behaviours can be added here.

I then open up the silverlight proj file in notepad(I know messy but until microsoft build it in as a feature thats the best I have got) and for environment resources I do something similar to below:

Replace app section...

<Compile Include="App.xaml.vb">
<DependentUpon Condition=" '$(Configuration)' == 'Debug' ">App.Debug.xaml</DependentUpon>
<DependentUpon Condition=" '$(Configuration)' == 'PRD' ">App.PRD.xaml</DependentUpon>
</Compile>

Replace environment resource with...

<Page Include="Dictionary\Environments\Debug.xaml" Condition=" '$(Configuration)' == 'Debug' ">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Dictionary\Environments\PRD.xaml" Condition=" '$(Configuration)' == 'PRD' ">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>

that way the application loads/builds with the correct files included and loads the initial app page. Within each app page I load the relevant resource file.

The final section I have to change is rather than reusing the following line of code in the app:

myService=New Service.ServiceClient

I write:

myService.Initialise() and use the following extension:

<Extension()>
Public Sub Initialise(ByRef Service As aService.aServiceClient, Optional ByVal Timeout As TimeSpan = Nothing)
Try
If IsNothing(Service) Then
Service = New aService.aServiceClient
End If
Service.Endpoint.Address = New EndpointAddress(App.Current.Resources("EndPointAddress").ToString) 'loaded from relevant resource file
If Timeout.TotalSeconds > 0 Then
Service.Endpoint.Binding.SendTimeout = Timeout
Service.Endpoint.Binding.ReceiveTimeout = Timeout
End If
Catch ex As Exception

End Try
End Sub

that way it initialises the service reference and uses the value in there to link into the endpoint.
3/12/2011 6:15 AM | # re: Managing service references and endpoint configurations for Silverlight applications
The infrastructure team uses powershell & msbuild to automate the configuration changes during forward or backward migrations between environments. I am disappointed to see that the Dev Tools team hadn’t come up with a better approach in VS2010. ASP.NET supports the new config file70-294 test templates, in my opinion this should have been a SL4 MB2-633 test feature as well with msbuild tasks to unzip, modify and repackage the XAP files with 70-448 test
MB2-631 test the correct URL information in the servicereferences.clientconfig file.





6/16/2011 3:05 PM | # re: Managing service references and endpoint configurations for Silverlight applications
Tim,

This article was so helpful it that got me into a whole lot of trouble. Here is the situation. I’m developing in VS2010 with Silverlight 4. The service connects to Oracle 10g with Oracle.DataAccess.dll 10.2.0.1. The service has no problem performing select and any DML SQL statement in the development environment. But after deploying the application the INSERT statements never even get to the Oracle server. There is no database error. The SELECT statements work just fine.

[OperationContract]
public string InsertUdsBoundary(string cityName)
{
using (Oracle.DataAccess.Client.OracleConnection connection = new Oracle.DataAccess.Client.OracleConnection())
{
try
{
int16 addressCount = -1;
int64 inserted = -1;
Oracle.DataAccess.Client.OracleCommand command = connection.CreateCommand();
sql = "select count(*) from my.addresses where city = '" + cityName) + "'";
command.CommandText = sql;
Oracle.DataAccess.Client.OracleDataReader reader = command.ExecuteReader();
while (reader.Read())
{
if (!DBNull.Value.Equals(reader[0]))
addressCount = Convert.ToInt16(reader[0]);
}
if addressCount > 0)
{
connection.Close();
return "There are " + Convert.ToString(addressCount) + cityName;
}
sql = "INSERT INTO my.addresses " +
"(address_id,city,address) " +
"select my.address_seq.NEXTVAL,'Houston','123 My Street' from dual";
command.CommandText = sql;
inserted = command.ExecuteNonQuery();
if inserted != 1)
{
connection.Close();
return "Unable to insert into your addresses table";
}
catch(Exception exp)
{
return exp.Message.toString();
}
finally
{
connection.close();
return "Done!";
}
}

No message is returned, which means the table was empty, there was no error otherwise the exception error would have come up. and it never got to the final. we turned on the database error log. not error was created. I appreciate any suggestion you have.
Gravatar
7/6/2011 6:36 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Nice article !!! This really helped me lot!!!
7/29/2011 12:10 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Hello, Tim. I use the approach with relative path in my client.config file, such as:

<endpoint address="../HelloWorldService.svc" />

But there is one problem: when i update service reference, visual studio add new endpoint with absolute address, because reference is configured with absolute address. And I need to manually revert client.config to it's previous state. Is it possible to avoid this?
8/3/2011 3:24 PM | # re: Managing service references and endpoint configurations for Silverlight applications
Tim, I really like this article BUT I can only get the service calls working with anonymous access (as the code comes). I get the dreaded NotFound as soon as I host the demo in IIS and disable anonymous access.

Does this solution work for you with Anonymous access disabled in IIS?

Thanks very much.
6/7/2012 5:15 AM | # re: Managing service references and endpoint configurations for Silverlight applications
Thanks Tim. Relative endpoint in web.config really rocks. That solved my problem.

 
Please add 4 and 8 and type the answer here:

DISCLAIMER:

The opinions/content expressed on this blog are provided "ASIS" with no warranties and are my own personal opinions/content (unless otherwise noted) and do not represent my employer's view in any way.