XML Transform on Silverlight ClientConfig Files

Monday, 08 March 2010 06:56 AM
by Coose

One of the most annoying parts of developing with WCF and Silverlight is the configuration files.  I have always hated WCF configuration files.  While powerful and necessary, they are just the opposite of fun.

Using Visual Studio 10 “publish” web functionality, the Web.Config files could be transformed with Web.Release.Config.  Not bad.  Makes things a little easier.  Here’s the rub: when creating a WCF/Silverlight application, the publish transformation would transform the web.config for the server, but NOT the ServiceReferences.ClientConfig on the client.  What a PITA.

Some Microsoft blogs show that the preferred solution for this problem is to rename the published .xap file to .zip, then open the .zip file, extract the .ClientConfig file, change it, save it, re-zip it, then rename the .zip back to .xap.

Really?

After the first time, this got so cumbersome I wanted to shoot myself.  Really I wanted to shoot someone at Microsoft. :)  Anyway, Google provided a few solutions, none totally to my liking.

My boss pushed the ConfigSwitcher project on me, as in theory it seems to be what I am looking for.  Being pre-VS2010, this didn’t use the XML transformation functionality but instead used a full copy of the config file, and required another .exe that had to be copied to each machine that this would be run on.  But it is a good idea.

So my strategy is to write custom build tasks that copy the ServiceReferences.ClientConfig file to a temp file before the build, then run the XML transformation using ServiceReferences.$(Configuration).ClientConfig and output to ServiceReferences.ClientConfig.  Then after the build completes, and the transformed file has been put into the .xap file, delete the ServiceReferences.ClientConfig, and copy the original file (which is now a temp file) back.

So…

Before Build:

  • Copy ServiceReferences.ClientConfig to ServiceReferences.Build.ClientConfig
  • Transform ServiceReferences.Build.ClientConfig to ServiceReferences.ClientConfig using ServiceReferences.$(Configuration).ClientConfig

and After Build:

  • Delete ServiceReferenes.ClientConfig
  • Move ServiceReferenes.Build.ClientConfig to ServiceReferences.ClientConfig

And, I don’t want any more baggage required.  I don’t want a program that has to be installed on developer machines, and I don’t want a macro that has to be present on developer machines.  I don’t even want custom MSBuild targets installed.  So, to do this, I use the BeforeBuild and AfterBuild target overrides of the .csproj file, and I use the already present XmlTransform task of Visual Studio 10.

So, unload the project and edit the .csproj file directly.  Scroll to the bottom and there are commented out BeforeBuild and AfterBuild overrides.  Adding this snippet:

  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />

  <Target Name="BeforeBuild" Condition="Exists('ServiceReferences.$(Configuration).ClientConfig')">

    <Move SourceFiles="ServiceReferences.ClientConfig" DestinationFiles="ServiceReferences.Build.ClientConfig" />

    <TransformXml Source="ServiceReferences.Build.ClientConfig" Destination="ServiceReferences.ClientConfig" Transform="ServiceReferences.$(Configuration).ClientConfig" />

  </Target>

  <Target Name="AfterBuild" Condition="Exists('ServiceReferences.Build.ClientConfig')">

    <Delete Files="ServiceReferences.ClientConfig" />

    <Move SourceFiles="ServiceReferences.Build.ClientConfig"

          DestinationFiles="ServiceReferences.ClientConfig" />

  </Target>

 

gives me what I want.  If there is a file named ServiceReferences.Release.ClientConfig and I am building a Release version, then the transformation is run at compile time, and the transformed .ClientConfig is put into the .xap file.

Comment on this
Development
|

Comments (3) -

KEG United States | Reply
9/28/2011 6:24:55 AM #
This is great!  Nice elegant solution.
Norman Harebottle United States | Reply
10/20/2011 9:15:44 AM #
This is great!  You ought to post this to www.stackoverflow.com if you haven't!  One question, I am getting all of the ServiceReferences.* files into the XAP file, did I miss a step somewhere or was that not handled by this solution?
Rodrigo Tisatto Brazil | Reply
12/18/2011 6:11:06 AM #
Hello! Adapted his idea for a simpler way to solve the problem:

- We have two files: ServiceReferences.Debug.Config and ServiceReferences.Release.Config.
- We used to copy in BeforeBuild using XML transformations to copy for ServiceReferences.Config to be used in the project.

Below the code as is - it works nice.

Thank you!

  <Target Name="BeforeBuild" Condition="Exists('ServiceReferences.$(Configuration).ClientConfig')">
    <Copy SourceFiles="ServiceReferences.$(Configuration).ClientConfig" DestinationFiles="ServiceReferences.ClientConfig" />
  </Target>

Pingbacks and trackbacks (1)+

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading