4

I have a silverlight 5 project in VS 2010 and would like to have its config file changed based on my configuration, pretty much like one would change database connection strings for a web app.

My ServiceReferences.ClientConfig looks like this:

<configuration>
<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_IWcfPortal" closeTimeout="00:10:00"
                openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
                maxBufferSize="25000000" maxReceivedMessageSize="25000000" />
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint name="WcfCslaService" address="http://localhost:22/Services/WcfSlPortal.svc"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IWcfPortal"
            contract="WcfPortal.IWcfPortal" />
    </client>
</system.serviceModel>

My ServiceReferences.MyConfig.ClientConfig file (auto added with slow cheetah via right click, add transform) looks like this:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.serviceModel>
    <client>
        <endpoint name="WcfCslaService" address="http://192.168.0.0:22/Services/WcfSlPortal.svc"
                  binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IWcfPortal" contract="WcfPortal.IWcfPortal"
                  xdt:Transform="Replace" />
    </client>
</system.serviceModel>

My problem is that instead of replacing the whole node (like it is doing in my web.config in this same solution) the transform doesn't happen. I have tried clean/rebuild, manually deleting .xap file, building one project at a time. If I look in my silverlight project\bin folder and unzip my xap file it ends up containing all the ClientConfig files, and the main config file left untouched. I also have an error in my xap file underlining the "xdt:Transform" that says "The 'http://schemas.microsoft.com/XML-Document-Transform:Transform' attribute is not declared."

If I right click on ServiceReferences.MyConfig.ClientConfig, Preview Transform it shows me exactly what it should (same service with updated IP address). The other crazy thing is that this was working previously and I have no idea what I did to break it (broke right before I went to commit to the repo). I have uninstalled and reinstalled slow cheetah, restarted etc.

Anyone know how to fix this transform to work?

Mario
  • 3,405
  • 6
  • 38
  • 48

2 Answers2

2

If all you're really trying to do is replace the address, then you might try something like this (note, I am not using SlowCheetah itself, but perhaps this indirect approach will give you enough insight to solve the problem). I'm using the built-in transformation mechanism and hooking into the BeforeBuild and AfterBuild MSBuild targets.

In ServiceReferences.ClientConfig.Template I have something like

<configuration>
  <system.serviceModel>
    <!-- ... -->
    <client>
      <endpoint
        name="Mine"
        address="http://localhost:8080/SomeService.svc"
        binding="basicHttpBinding"
        bindingConfiguration="..."
        contract="..."/>
    </client>
  </system.serviceModel>
</configuration>

And to replace the address, I use the transform

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.serviceModel>
    <client>
      <endpoint
        xdt:Locator="Match(name)"
        xdt:Transform="SetAttributes(address)"
        name="Mine" 
        address="http://SomethingElse/Services/SomeService.svc"/>

If you're trying to replace the whole node, I haven't tried that, but while a pain, you could probably remove all the attributes you don't want then add new ones.

To kick off the transformation that creates the real ServiceReferences.ClientConfig, I have the following in my Silverlight .csproj file:

  <Target Name="BeforeClean">
    <Delete Files="ServiceReferences.ClientConfig" />
    <Message Importance="High" Text="***** Deleted generated ServiceReferences.ClientConfig" />
  </Target>
  <Target Name="BeforeBuild" Condition="Exists('ServiceReferences.$(Configuration).ClientConfig')">
    <!-- this is the file that ultimately we want to populate in a .xap, but this is also not version controlled; effectively it's always generated -->
    <Delete Files="ServiceReferences.ClientConfig" />
    <!-- transform the template -->
    <TransformXml Source="ServiceReferences.Template.ClientConfig" Destination="ServiceReferences.ClientConfig" Transform="ServiceReferences.$(Configuration).ClientConfig" />
    <Message Importance="High" Text="***** Generated ServiceReferences.ClientConfig from ServiceReferences.Template.ClientConfig and ServiceReferences.$(Configuration).ClientConfig" />
  </Target>
  <Target Name="AfterBuild" />

Some other (probably already setup correctly in your solution) "obvious" things to check include:

  • Make sure your Silverlight project properties has the correct .xap name and generates a Silverlight manifest file.
  • Make sure your web host project for the Silverlight app contains the name of the above project, and that it is placed in ClientBin for Path in Web.
  • Make sure the dependencies and build order for the two projects are correct
Kit
  • 20,354
  • 4
  • 60
  • 103
  • Kit, thanks for the answer. I swear I tried adding the Locator in there a few times and it didn't work. I pasted this in, changed a few things and now the .xap has the proper config file in the silverlight project, but when I publish the web project the .xap file that is included in the ClientBin folder has the non-transformed config – Mario Aug 16 '12 at 14:32
  • scratch that. When i cleaned and rebuilt again even the silverlight project .xap doesn't contain the transformed config anymore - I am back to my original problem. When you do this transform in your project do you see it carry over to ..\yourWebProj\ClientBin\YourSLProj.xap? – Mario Aug 16 '12 at 15:13
  • I updated my answer in hopes it gets you closer. I'm not actually using SlowCheetah, but maybe there's enough detail here it can help get you to the solution. Feel free to add to the answer if you nail it. – Kit Aug 17 '12 at 14:50
  • Kit, what is ServiceReferences.Template.ClientConfig? Is it a custom template you made? – Mario Aug 31 '12 at 15:23
  • @Mario - yes. Basically wanted to have a template and the ServiceReferences.*Env*.config files to be version controlled, but not the ServiceReferences.ClientConfig, because it's generated. – Kit Aug 31 '12 at 16:26
2

Thanks to Kit for the help. I finally got a little time to look into this and deploy to a few different servers using different configurations and came up with the following solution:

  1. Make sure Web project properties build output path is \bin\ and configuration specific folders is set to No in the Silverlight Applications section of project properties
  2. Make sure Silverlight project properties build output path is \bin\ (this was my first problem)
  3. Either use Slow Cheetah (easy) or modify the csproj xml of the silverlight project (kind of a pain but not bad once done once - here is the link to allow you to have configuration specific transforms for your ServiceReferences.ClientConfig file). With slow cheetah you can view your transform by right clicking on the configuration specific transforms. Both mine and Kit's transform work.
  4. Add xml (taken from the above link) into the silverlight project (csproj) file. It is similar to Kit's but not sure why his wouldn't compile and this one would (This was my second problem) - xml below
  5. Rebuild project, then publish. The .xap will have your transformed ServiceReferences.ClientConfig file in it.
  6. Add the MyProject.Publish.Xml to your repository if you would like to share your deployment configurations with your whole team
 <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>
Community
  • 1
  • 1
Mario
  • 3,405
  • 6
  • 38
  • 48