Visual Studio App.config XML Transformation

Visual Studio 2010 introduced a much-anticipated feature, Web configuration transformations. This feature allows to configure a web application project to transform the web.config file during deployment based on the current build configuration (Debug, Release, etc).

If you haven’t already tried it there is a nice step-by-step introduction post to XML transformations on the Visual Web Developer Team Blog and for a quick reference on the supported syntax you have this MSDN entry.

Unfortunately there are some bad news, this new feature is specific to web application projects since it resides in the Web Publishing Pipeline (WPP) and therefore is not officially supported in other project types like such as a Windows applications. The keyword here is officially because Vishal Joshi has a nice blog post on how to extend it’s support to app.config transformations.

However, the proposed workaround requires that the build action for the app.config file be changed to Content instead of the default None. Also from the comments to the said post it also seems that the workaround will not work for a ClickOnce deployment.

Working around this I tried to remove the build action change requirement and at the same time add ClickOnce support. This effort resulted in a single MSBuild project file (AppConfig.Transformation.targets) available for download from GitHub. It integrates itself in the build process so in order to add app.config transformation support to an existing Windows Application Project you just need to import this targets file after all the other import directives that already exist in the *.csproj file.

Before – Without App.config transformation support

  ...
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
</Project>

After – With App.config transformation support

  ...
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="C:\MyExtensions\AppConfig.Transformation.targets" />
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
</Project>

As a final disclaimer, the testing time was limited so any problem that you find let me know. The MSBuild project invokes the mage tool so the Framework SDK must be installed.


Update:

I finally had some spare time and was able to check the problem reported by Geoff Smith and believe the problem is solved. The Publish command inside Visual Studio triggers a build workflow different than through MSBuild command line and this was causing problems. I posted a new version in GitHub that should now support ClickOnce deployment with app.config tranformation from within Visual Studio and MSBuild command line.

Thanks to Geoff for spotting the problem.


Update 2:

There’s a new version available at GitHub that includes a fix by Ryan Milligan for a ClickOnce deployment problem. I did some minor changes to Ryan’s fix, but I did some tests and I believe I didn’t mess it up.

Thanks again to Ryan for finding the problem and fixing it.

About these ads
Leave a comment

73 Comments

  1. Brilliant… well done on a very clean work around

    Reply
  2. tim

     /  June 26, 2010

    I’ve been reading both yours and Vishal’s posts, and this is great… but it doesn’t allow for multiple files to be transformed

    Reply
  3. Ajay

     /  June 27, 2010

    I was looking for this exactly and was half way through writing something. Glad I came across your post. Thanks for providing this.

    One question – we are signing the deployment manifest. Any idea if your BeforePublish/AfterPublish overrides will make the signature invalid?

    Reply
    • João Angelo

       /  June 28, 2010

      The signing is performed after the BeforePublish so the process of updating the manifest should not affect it. The AfterPublish target only performs a copy of the transformed App.config which to my knowledge should also not affect the signing process.

      However, if you find any problem say something.

      Reply
  4. Geoff Smith

     /  August 4, 2010

    Hi, I’m trying to get going with your solution but the click once side of things doesn’t seem to be working. My app.config is appearing in the build directory but not in the published files.

    I’m trying to debug it to figure out what’s happening. I’ve added elements in the 3 targets: CopyTransformedConfig, BeforePublish and AfterPublish but am not seeing anything in the logs.

    This is my first foray into msbuild, do you have any tips for checking that the targets are actually running.

    Reply
    • Geoff Smith

       /  August 4, 2010

      Interestingly it works when I run msbuild manually, but not from the IDE

      Reply
    • João Angelo

       /  August 4, 2010

      Since you say that the app.config in build directory is correctly transformed than the targets that may not be running or running with an error are the BeforePublish and AfterPublih.

      You can use the MSBuild Message Task inside each target element for debugging purposes. Also run MSBuild directly from the command line instead of letting VS invoke it.

      For example, from VS 2010 command prompt:
      msbuild MyProjectWithAppConfigTransform.csproj /t:Publish

      If the problem persists create a sample project where the error occurs and provide me with a link to download it, so I can check what’s wrong.

      Reply
      • João Angelo

         /  August 4, 2010

        If the problem manifests itself only from within VS I’m a little lost on the possible causes, but if you can provide the sample project I will try to investigate the issue.

    • Geoff Smith

       /  August 5, 2010

      I’m making progess, the AfterPublish target didn’t recognise TransformedConfig, I guess it wasn’t in scope somehow. Once I copied the definition from CopyTransformedConfig into AfterPublish, it worked fine. No idea why the scoping would be different when I run msbuild manually.

      I’m now stuck at the manifest file, it’s not being generated against the transformed app.config. I’m starting to get the hang of msbuild now so should be able to figure it out. I’ll report back once I have :)

      Reply
      • João Angelo

         /  August 5, 2010

        I think I may know what’s going on. The Publish in Visual Studio may be skipping the Build phase since it detects that the binaries are up-to-date which in turn causes CopyTransformedConfig to not run.

        To check this you can first do a Clean and then a Publish in VS, which should force the full build process like what it happens in executing MSBuild from command line.

        As soon as I have some time I’ll check this and try to find a better solution.

      • Geoff Smith

         /  August 5, 2010

        I just tried it with a clean before publishing, but it didn’t help. Same problem with TransformedConfig missing.

    • Geoff Smith

       /  August 5, 2010

      Got it working :) I fixed the manifest problem by copying the re-generated manifest back into the IntermediateOutputPath. I had to do this because _CopyManifestFiles was overwriting the manifest you had updated in BeforePublish.

      It’s a bit of a hack, when I have some more time I might take a look at how to improve it. Anyways, thanks for the script and your help!

      Reply
      • João Angelo

         /  August 27, 2010

        Geoff, I posted an updated version on GitHub that should fix the problem you experienced.

      • Leonardo Pignataro

         /  September 1, 2010

        I’m having the same problem as Geoff, and I’m already using the updated version of AppConfig.Transformation.targets, so it seems it did not fix the problem…

      • João Angelo

         /  September 1, 2010

        Can you provide a link for an example project where the error occurs? I also updated the post with a link to the sample application used to test the new version. Check if publishing it with the configurations described in the post work for you.

      • Leonardo Pignataro

         /  September 1, 2010

        Below is a link for a sample project.

        http://rapidshare.com/files/416495688/SampleApp.rar

        The AppConfig.Transformation.targets is in the project directory, and is being integrated with the following line:

        <Import Project="$(ProjectDir)AppConfig.Transformation.targets" />
        

        The transformation works fine, but if you select the Release configuration and ask VS to publish the project, it fails:

        Unable to copy file “obj\x86\Release\TransformWebConfig\transformed\App.config” to “bin\Release\app.publish\Application Files\SampleApp_1_0_0_6\SampleApp.exe.config.deploy”. Could not find file ‘obj\x86\Release\TransformWebConfig\transformed\App.config’.

      • João Angelo

         /  September 2, 2010

        In your sample application you only have a transformation file for the Debug config (App.Debug.config) and in my limited tests I always assumed that it would exist one transformation file for each build configuration. If you add a App.Release.config file with just the skeleton of a transformation file without even needing to do any specific transformation the current version will work for you.

        <?xml version="1.0" encoding="utf-8" ?>
        <configuration 
          xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
        </configuration>
        

        This is just an workaround and I will try to handle this scenario as soon as I have some free time.

      • Leonardo Pignataro

         /  September 2, 2010

        YES! It works! THANK YOU VERY MUCH!!!

        Actually, for me it’s even better having both the .Debug and .Release files. For some reason I wrongly assumed that your method was intended for using only the .Debug file. Maybe Geoff is doing the same?

        (actually I know why I thought that, it’s because in Vishal Joshi’s post he only uses the .Debug file, and I read his post before yours, so I got confused…..)

        I don’t even think it’s that useful handling this only-Debug-file scenario, why not have both files, right?

        For anyone out there trying this method, you can do with this method the step on Vishal Joshi’s post about altering the project file to make the App.Debug.config and App.Release.config “DependentUpon” App.config, so that the two files appear as child nodes of the App.config file on the Solution Explorer window. However, as João says, with his method you should not change the file’s node from “None” to “Content”. So, that means replacing

        <None Include=”App.config” />
        <None Include=”App.Debug.config” />
        <None Include=”App.Release.config” />

        with

        <None Include=”App.config” />
        <None Include=”App.Debug.config”>
        <DependentUpon>App.Config</DependentUpon>
        </None>
        <None Include=”App.Release.config”>
        <DependentUpon>App.Config</DependentUpon>
        </None>

        Again, a big THANK YOU to João Angelo :-)

  5. I solve this problem with this tool http://ctt.codeplex.com/, I execute with CCNet/nAnt at build server.

    Reply
    • João Angelo

       /  August 27, 2010

      I checked your application and it looks very useful for transforming regular XML files. For app.config files it seems to lack support for ClickOnce support which is a weak point.

      Reply
  6. MartinD

     /  September 15, 2010

    Your solution works fine. But there’s one problem. All was fine until I enabled RSAencryption for my data connections (Using Enteprise Library 5), which made following change to App.config

    <add name="EasyTestConnectionString" connectionString="Data Source=.\sqlexpress;Initi

    changed to ————————————

    AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAH2…

    Can You help solve this situation ?

    Reply
    • João Angelo

       /  September 15, 2010

      I can try to help, but you need to be more specific in what the problem is. You enabled encryption and the XML transformations fail to produce a valid App.config file, is that it?

      Reply
      • MartinD

         /  September 15, 2010

        If i got it right, so I take my configuration which looks like this:

        and add folowing text to configuration “xdt:Transform=”Replace” xdt:Locator=”Match(name)”‘ for the transformation to work.

        after doing so, Enterpise lib. says that connection string setting is invalid, so I cannot use the EntLib to protect (encrypt) sensitive info in the connection string

      • João Angelo

         /  September 15, 2010

        I would recommend you to the following, post a download link to a sample project that exhibits the problem in question and I’ll try to take a look as soon as have some free time which may take a while.

        Another option would be for you to post a question in Stack Overflow with the details and send me a link, this way maybe someone else also had the problem and you may get an answer sooner.

  7. Doesn’t seem to work when click-once publishing a WorkerRole to Azure. Could be my settings, but I’m not so sure. Have you tested this with Azure publishing?

    Reply
    • João Angelo

       /  October 4, 2010

      David, the targets weren’t tested with Azure publishing.

      I’m not familiar with the process of directly publishing a ClickOnce application to Azure, but isn’t possible as a workaround to publish locally and then copy the files?

      Reply
  8. Chris

     /  October 11, 2010

    Our team had already implemented a different solution to this problem, but this solution is much easier to understand. Simple and easily deployable to our CI server. Thank you.

    Reply
  9. Hi,

    I’ve tried solutions from here as well as the one from Vishal’s blog. However, it so seems that the transformation works when built on a dev machine. However, the transformation when built on the Team build server seems to happen after the files have been dropped to the drop target.
    Not sure how to fix this.

    Any help would be appreciated.

    Thanks
    Bala

    Reply
    • João Angelo

       /  October 25, 2010

      I’m afraid I can’t be of any assistance since I have no experience in working with TFS build servers.

      Reply
  10. Great post but I have some problems when the config files are not in the root of the project structure (like in a subdirectory called config). Any ideas how I need to modify the targets file to take that into account?

    Reply
    • João Angelo

       /  November 11, 2010

      I’ll need to verify if it’s possible, but assuming that the native Web.config transformations support the placement of config files in sub-directories then it should also be possible to support it for App.config files. I’ll check this feature as soon as I have some time.

      Reply
  11. Mickaël

     /  November 16, 2010

    Hi,

    I have set a postbuild event in my project to crypt the appsettings with a powershell script.
    It’s not working when I include your targets file. Can you tell me why please ?

    http://rapidshare.com/files/431177833/Example-PostBuildEvent.zip

    Thanks

    Reply
    • João Angelo

       /  November 30, 2010

      Your postbuild event runs before the target CopyTransformedConfig which is the target responsible for copying the transformed config file from its temporary location to the output path which means that your encryption is being overridden. There’s also the problem that you are encrypting the unstransformed version of the App.config and not the transformed one. A possible workaround would be for you to edit the targets file and call Powershell from MSBuild and after the copy of the transformed config file.

      Reply
      • Mickaël

         /  December 1, 2010

        Can you tell me how to add this step in the targets file please ?

  12. shlomiw

     /  November 18, 2010

    Thanks you very much!

    Reply
  13. Rick

     /  December 3, 2010

    I had an issue with the CopyTransformedConfig that it wasn’t copying the transformed config to the drop folder when I ran a build on a TFS build server. I updated the DestinationFiles to use OutDir instead of OutputPath and it works fine. Still works in Visual Studio as well.

    Reply
  14. Mickaël

     /  December 16, 2010

    Hi,

    The transformation seems to be broken with vs2010 Sp1 with clickonce publishing. Someone can confirm that please !?

    Reply
  15. Mickaël

     /  December 16, 2010

    Yes, with pleasure… :)

    Reply
  16. Thanks for this! You’ve brought joy to my day that would have been otherwise spent buried in tedious custom XML transforms.

    Reply
  17. Thank you so much, works like a charm!

    Reply
  18. Ryan Milligan

     /  February 24, 2011

    I love the simplicity of this solution. I have only run into one problem when publishing from Visual Studio. It appears that some of the files are not being found during manifest update time (Exec Command=”$(MageTool) -update $(GeneratedManifestFile)”). The files seem to be dlls that aren’t copied to the output folder and content files that are set to not copy to the output folder. Any ideas why this would be happening and how it can be fixed?

    Reply
    • João Angelo

       /  February 24, 2011

      Ryan, from the top of my head I’m unable to provide you with a workaround, but if you can provide a download link to sample project with the problem I can take a look at it as soon as possible.

      Reply
  19. Ryan Milligan

     /  February 24, 2011

    I have uploaded a sample app here:

    http://dl.dropbox.com/u/7321716/AppConfigTargets/TestAppForAppConfigTransformations.zip

    There is also a screenshot of the Application Files window for the publish that I think is related:

    The Infragistics DLLs are installed in my GAC, so I need to change the publish status to Include in order for the publish to succeed. This causes the DLLs to be copied to the publish path, but doesn’t copy them to the normal build path where it looks like the build task is looking to reupdate the manifest.

    Reply
  20. Ryan Milligan

     /  February 25, 2011

    I have been working on this all day and came up with a modified targets file that seems to work. Rather than trying to update the manifest and re-sign it, I hoodwinked MSBuild to consider the new config file to be the config file it cares about. I have uploaded the modified targets file here:

    http://dl.dropbox.com/u/7321716/AppConfigTargets/AppConfig.Transformations.targets

    Reply
    • João Angelo

       /  February 25, 2011

      Thanks Ryan, that seems the more robust solution to the problem in hand. I’ll just be doing some tests and I’ll include your fix in GitHub if everything works as expected.

      Reply
    • João Angelo

       /  February 25, 2011

      Ryan, I updated the targets file available in GitHub to include your fix. I made some minor changes like extracting your fix to a new target, hope you don’t mind.

      Reply
      • Ryan Milligan

         /  February 25, 2011

        Cool. I don’t mind at all. I’m glad I could contribute to this solution.

      • Ryan Milligan

         /  March 11, 2011

        I updated VS2010 to SP1 yesterday and this broke. I did, however, find a solve by overriding some additional parts of the MS Web targets. Adding the following to the targets file will resolve the issue I found:

        <!– Override this target and property group to make it do nothing–>
        <PropertyGroup>
        <!–Targets get execute before this Target–>
        <OnBeforeCollectFilesFrom_binDeployableAssemblies />
        <!–Targets get execute after this Target–>
        <OnAfterCollectFilesFrom_binDeployableAssemblies />
        <CollectFilesFrom_binDeployableAssembliesDependsOn />
        </PropertyGroup>
        <Target Name="CollectFilesFrom_binDeployableAssemblies"
        DependsOnTargets="$(CollectFilesFrom_binDeployableAssembliesDependsOn)">
        </Target>
        
      • João Angelo

         /  March 13, 2011

        Yes, that was a known problem that already manifested in the VS SP1 BETA. I already published a quick workaround for the SP1 BETA and will now be testing it in the final release and probably integrating in the original targets file unless it causes problems in the RTM version of VS. If that’s the case I will continue to maintain two separate versions of the targets file.

  21. Sujith Gowda

     /  March 1, 2011

    Joao Angelo,
    Your solution doesnt work for the setup deployment project associated with Windows service OR Windows Applications. It looks like the setup always copies the default app.config and does NOT copy the transformed one.

    Do you have any workarounds?

    Reply
    • João Angelo

       /  March 1, 2011

      Hi Sujith, I don’t have any workarounds for what you described but I’ll try to look into it.

      Reply
  22. Cole

     /  March 2, 2011

    This is really slick. It’s quite nice and solves a problem that I’m surprised isn’t solved elsewhere.

    Oleg has instructions that work with Azure project config files as well: http://www.olegsych.com/2010/12/config-file-transformation/#comment-3370

    It’d be really cool if you split that out into an includable .targets file as you’ve done with the App.config transformations. You could foster a little collection of handy add-ins to make project configuration changes a bit easier.

    Additionally, I’m looking for a method by which I could have Web.config in my Web Project be transformed EVERY build, not just in builds for package/publish.

    Any ideas how I’d go about that?

    Thanks for the awesome contribution, this beets copy/pasting any day.

    Reply
  23. Cole

     /  March 11, 2011

    Another question…

    During Azure solution building, I can watch the App.config be transformed, I can see the transformed XML in my Worker Roles’ bin/obj folders…

    but it seems that the Azure packer just completely ignores the transformed App.config. Meaning when I try to deploy in release mode, my staging environment worker roles are broken since their connection strings are not updated.

    Any ideas how I could get this working with Azure projects? I’m about to give up on transforms altogether and try this: http://stackoverflow.com/questions/3004210/app-config-transformation-for-projects-which-are-not-web-projects-in-visual-studi/4977477#4977477

    Thanks for any info.

    Reply
    • João Angelo

       /  March 13, 2011

      Hi Cole, the problem you describe seems to be similar to one that happens when using VS setup deployment projects. It seems that the setup deployment project and Azure packer always pick the original App.config at the project root, ignoring the one transformed and copied to the output directory. If I have any breakthrough with these problems I’ll let you know.

      Reply
  24. Raj

     /  March 15, 2011

    I am trying to implement the App.config Transformations in a ClickOnce app and its working really good in my local, vs2010 is creating a one more App.config with build Action “FilesForPackagingFromProject”. when i checked in (TFS) the code I am getting an exception c:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(2580,9): error MSB3113: Could not find file ‘obj\x86\Debug\TransformWebConfig\transformed\App.config’. [C:\Folder\ClickOnce.Deployment.csproj]

    Reply
    • João Angelo

       /  March 15, 2011

      Hi Raj, the transformation targets were never tested in TFS so the fact that you’re getting errors does not surprise me. It’s my intention to provide compatibility for TFS, Azure and Setup Deployment projects, but the backlog of things to do is just increasing and free time is something I’m lacking in the next weeks. I also don’t have a TFS environment on where to perform the tests so it increases the unlikeliness of me fixing the problem in the near future.

      Reply
  25. I love this and it works really great. However, I’m getting errors unless I have the transformation xml in a path with no spaces. Anyone else having this issue? I work on several different development machines and the code repository path has spaces in it. It’s forcing me to save a copy on the local drive for each of my development machines rather than having it in the solution folder.

    Any tips would be welcome.

    Reply
  26. Aweomse, thanks. This worked fist time for me after mucking around with SlowCheetah on the TeamCity build server for ages….

    Reply
  1. Making use of configuration file transformations in SharePoint 2010 « Johan Leino
  2. Applying app.config transformations (in the same way as web.config) - James Crowley
  3. VNX » Blog Archive » How to integrate separate config files for Debug and Release-mode in Windows applications
  4. Applying app.config transformations (in the same way as web.config) | Coding, content and startups
  5. Managing app.config for different environments | 1–5% of the population
  6. Use app.config transformation in WPF projects with ClickOnce publishing « Tips and tricks around code-world
  7. How to use config transforms with MSBuild | How Do I Do That Again?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 27 other followers