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.

76 thoughts on “Visual Studio App.config XML Transformation”

  1. 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

  2. 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?

    1. 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.

  3. 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.

    1. 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.

      1. 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.

    2. 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 🙂

      1. 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.

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

    3. 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!

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

      2. 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…

      3. 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.

      4. 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’.

      5. 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.

      6. 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 🙂

    1. 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.

  4. 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 ?

    1. 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?

      1. 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

      2. 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.

  5. 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?

    1. 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?

  6. 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.

  7. 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

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

  8. 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?

    1. 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.

    1. 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.

  9. 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.

  10. Hi,

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

    1. Hi Mickaël,
      thanks for reporting the issue with VS2010 SP1 Beta. However, due to time restrictions I’ll probably wait for the final release to try to make the transformation compatible.

      On a side note, do you still need help in adding the encryption step into the targets file?

      1. I wasn’t aware of that bug. In the next couple of days I will try to take a look at the problems arising with SP1 beta and try to provide support for it.

      2. Anthony, I posted a new version where I fixed the build errors I found when used with VS 2010 SP1 BETA. Sorry to take so long. If you find any problems with this new version and SP1 BETA let me know. Thanks.

  11. 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?

    1. 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.

  12. 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.

    1. 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.

    2. 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.

      1. 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>
        
      2. 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.

  13. 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?

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

  14. 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.

  15. 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.

    1. 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.

  16. 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]

    1. 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.

  17. 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.

Leave a reply to Ryan Milligan Cancel reply