Scott Hanselman

SlowCheetah - Web.config Transformation Syntax now generalized for any XML configuration file

August 23, '11 Comments [71] Posted in ASP.NET | Tools
Sponsored By

I did a post last year called If You're Using XCopy, You're Doing It Wrong that also included a video of my talk at Mix10 where I show how to deploy website with Web Deploy. One of the cooler not-very-well-known features is called Web.config Transformation. Once folks see it, then immediately want a general solution.

First, from the previous post:

You can right-click on your web.config and click "Add Config Transforms." When you do this, you'll get a web.debug.config and a web.release.config. You can make a web.whatever.config if you like, as long as the name lines up with a configuration profile. These files are just the changes you want made, not a complete copy of your web.config.

You might think you'd want to use XSLT to transform a web.config, but while they feels intuitively right it's actually very verbose.

Here's two transforms, one using XSLT and the same one using the XML Document Transform syntax/namespace. As with all things there's multiple ways in XSLT to do this, but you get the general idea. XSLT is a generalized tree transformation language, while this deployment one is optimized for a specific subset of common scenarios. But, the cool part is that each XDT transform is a .NET plugin, so you can make your own.

<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
  <xsl:copy>          
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="/configuration/appSettings">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
    <xsl:element name="add">
      <xsl:attribute name="key">NewSetting</xsl:attribute>
      <xsl:attribute name="value">New Setting Value</xsl:attribute>
    </xsl:element>
  </xsl:copy>
</xsl:template>
</xsl:stylesheet>

Or the same thing via the deployment transform:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add name="NewSetting" value="New Setting Value" xdt:Transform="Insert"/>
</appSettings>
</configuration>

This kind of config file transformation is so useful in fact, that it's one of the #1 feature requests...as a generalized solution. Folks want to transform their app.configs, or any XML file as part of their builds. Additionally, the current system only runs the transforms as a part of the publish process and folks would rather the transform happen "on F5" or on build. So, my team members Sayed Ibrahim Hashimi and Chuck England have done just that as a small VSiX called SlowCheetah XML Transforms.

In this screenshot I've created a simple Console Application, made a basic app.config, then right clicked and selected "Add Transform." This gives an app.debug.config and app.release.config. You could make and name these however you like, for example app.testing.config, etc.

An app.config file, the transform file, and the result in three panes

For example, here's a basic app.config for my Console app:

<?xml version="1.0" encoding="utf-8" ?>
<configuration >
<appSettings>
<add key="appName" value="Something"/>
<add key="url" value="http://hanselman.com/"/>
<add key="email" value="awesome@hanselman.com" />
</appSettings>
</configuration>

And here's the transform to change my one value in my development time config to a debug value (or test, staging, etc). You can do this for connectionStrings, app keys, compiler settings, anything in an XML or config file.

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="appName" value="Demo-debug" xdt:Transform="Replace" xdt:Locator="Match(key)"/>
<add key="email" value="debug@contoso.com" xdt:Transform="Replace" xdt:Locator="Match(key)"/>
</appSettings>
</configuration>

Note the Transform="Replace?" That can be replace, or insert, etc. Lots of choices. The ShowCheetah XML Transform Add-In also adds a "Preview Transform" right-click menu which makes writing these way easier.

The clever part is that there's no magic. All the functionality is installed to %LOCALAPPDATA%\Microsoft\MSBuild\SlowCheetah\v1\ and lives in a standard MSBuild .targets file. You don't even need the plugin if you are installing this on a build server, just copy the files or even check them in with your source and refer to them in your project or MSBuild files. It's added in your project file for you via the tooling like any custom targets:

<Import Project="$(LOCALAPPDATA)\Microsoft\MSBuild\SlowCheetah\v1\Microsoft.Transforms.targets" Condition="Exists('$(LOCALAPPDATA)\Microsoft\MSBuild\SlowCheetah\v1\Microsoft.Transforms.targets')" />

Between the build targets and the added menu items, you get:

  • Added tooling to desktop project to create XDT transforms
  • Ability to transform
    • app.config for desktop projects based on build configuration
    • any XML file to the output folder based on build configuration
  • Added tooling to enable previewing XDT transforms
  • For web projects you can easily transform other XML files during package/publish

Let Sayed and the team know what you think, if it's useful, and if you use it at Sayed's blog, or the SlowCheetah project site on the VS Gallery. Enjoy!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Tuesday, August 23, 2011 9:07:35 AM UTC
For the XSLT example, it would be more educational to use Attribute Value Templates:
<add key="{NewSetting}" value="{New Setting Value}"/>
RichB
Tuesday, August 23, 2011 9:08:07 AM UTC
Great stuff! Ofcourse adding transformations to other config files is really nice, but I LOVE the Preview feature!
Thanks! :-)
Tuesday, August 23, 2011 9:34:59 AM UTC
Great stuff to read.
How would one then write a transform for something like this?

<applicationSettings>
<FileListnerTester.Properties.Settings>
<setting name="ListenPath" serializeAs="String">
<value>c:\temp\listner\</value>
</setting>
</FileListnerTester.Properties.Settings>
</applicationSettings>


And i wanted to change the <value> for <setting name="ListenPath" ?


Tuesday, August 23, 2011 9:45:58 AM UTC
The thing to remember about the transforms is the markup of the document acts as the "query" to find the element.

So for your example (my changes emphasised):


<applicationSettings>
<FileListnerTester.Properties.Settings>
<setting name="ListenPath" xdt:Locator="Match(name)">
<value xdt:Transform="Replace">c:\temp\listner\</value>
</setting>
</FileListnerTester.Properties.Settings>
</applicationSettings>


This says (if I remembered my transform syntax right!) Look inside applicationSettings & FileListnerTester.Properties.Settings to find a setting tag matched on the name attribute. Inside that replace the value tag.
Tuesday, August 23, 2011 10:03:04 AM UTC
Thanx Adrian, works like a charm :)
Tuesday, August 23, 2011 10:13:27 AM UTC
This is a great feature, but I hope that Azure SDK team can simplify this for Azure deployments. What I'm doing now in order to deploy to Azure and use the transforms is to edit the Azure project file's MSBuild and I think that's the only way to achieve this for Azure. As you can guess, it's something like rewriting the transformers by hand, so there is no fun for Azure users ;-)
Tuesday, August 23, 2011 10:59:29 AM UTC
Just yesterday I was talking with a coworker about how I wanted web.config transforms to be available for app.config files so I could set the correct setting in the unit tests assembly of our project. Great!

When adding this kind of feature in VS, there should be no limitation like this. It is a great feature that should be available at least to all .config files by default in VS.
Tuesday, August 23, 2011 12:52:08 PM UTC
The problem I have with the feature is that it misses the mark in my opinion. What I would really like is if this feature actually made it's way to a deployment package so I could use msdeploy to specify where I want to deploy it.

Most enterprise developers would want 1 package with 3 deployment options (qa, stage, prod for example), not the ability to create 3 separate packages based on my visual studio solution configuration.

MSDeploy is a wonderful tool, but seems to me the web.config transform that works pretty well in visual studio is at best a nice tool for developers, but does little to ease deployment scenarios.
chris haas
Tuesday, August 23, 2011 3:15:56 PM UTC
This is a great step in the right direction, but for many apps this is still only a partial solution. For example, many web and desktop apps employ some sort of plugin model. Often these plugins need to modify config settings where this framework would be extremely useful. In DotNetNuke we actually built our own several years ago using XSLT, but as you point out, it ended up being a little verbose. We also use the framework so that DotNetNuke can update it's own web.config when upgrading from one version to another. I would love to be able to replace that solution with one that is more widely supported and easier to grok for new developers.
Tuesday, August 23, 2011 3:56:05 PM UTC
Why is it that whenever someone is trying to sell XDT over XSLT, they exaggerate the verbosity of the XSLT (here: xsl:element, and xsl:copy rather than xsl:copy-of)?

It really undermines the argument.

Maybe it's related to the triviality of the examples given. It'd be interesting to have a StackOverflow Config Transform Build-Golf Contest with more realistic, comprehensive tasks, that pits XDT against XSLT.

Also, maybe the XSLT wouldn't be as verbose if Microsoft would finally implement XSLT 2.0/XPath 2.0.
Tuesday, August 23, 2011 3:56:50 PM UTC
RE: How to transform applicationSettings
The suggested solution works and the transform below also works:


<applicationSettings xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<FileListnerTester.Properties.Settings>
<setting name="ListenPath" serializeAs="String">
<value xdt:Transform="Replace">c:\temp\listner222\</value>
</setting>
</FileListnerTester.Properties.Settings>
</applicationSettings>
Tuesday, August 23, 2011 5:09:08 PM UTC
I really like if Jason Zander and his team make *.config available to all configs in Visual Studio.
Tuesday, August 23, 2011 5:19:47 PM UTC
I prefer to use T4 templates for the various satellite configs (local debug, dev, qa, etc). A little simpler, and way more concise.
Only a couple drawbacks: T4 markup in the XML confuses the text editor in Visual Studio; and warnings during text template transformations cause the build to fail on the build server (don't ask me why).
tb
Tuesday, August 23, 2011 5:58:45 PM UTC
Brian - It's not my, or anyone's intent to "sell" XDT over XSLT. XSLT (which, I used to be really good at, nearly 10 years ago) is a general tree transformation language. XDT is good for adds, inserts and replaces, NOT transforms.

If you can help me with a better XSLT example (or a 1.0 and 2.0 one) I will update the post!
Tuesday, August 23, 2011 7:23:43 PM UTC
I just meant "sell" in the general sense, that you were putting XDT code next to XSLT code to make the case that XDT is better suited to a given task than XSLT.

XDT aims to create a new syntax to optimize for the simple add, insert and replace cases of transformations. I haven't seen enough competition between the advocates of both technologies on real-world config changes to persuade me how well it has succeeded yet.

Maybe it's just me, though. The new syntax is probably not a prohibitive barrier to entry, and it's may be very rare to require config file changes significant enough that XDT cannot produce the desired result as effectively as XSLT.

The optimizations I was thinking of, just offhand:

<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
<xsl:copy-of select="@*|node()"/>
</xsl:template>
<xsl:template match="/configuration/appSettings">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<add key="NewSetting" value="New Setting Value"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Tuesday, August 23, 2011 7:29:09 PM UTC
(Hmm… scratch that xsl:copy-of. That's not going to work.)
Tuesday, August 23, 2011 8:07:29 PM UTC
Thanks Brian. I hear what you're saying. I do believe that for basic "replace this" type transforms that XDT is more intuitive for me and beginners.
Tuesday, August 23, 2011 8:15:53 PM UTC
I'm happy there's another option, but as the build guy on my team, I just wish people would stop putting stuff in app.configs and web.configs in general. I'd prefer people stored their configuration in either end-user-accessible database tables, or developer-accessible code (as in, C#). For the 2% that can't or shouldn't be stored in code or the database, server-admin-just-in-time-accessible-encryptable-and-easily-tweakable .config files are fine.

Unfortunately everyone's just been trained to throw whatever they need in the config file and hack together manual deployments.
Peter
Tuesday, August 23, 2011 9:22:11 PM UTC
Scott, I'm using Chrome 13.0.782.215 to read your blog and the Syntax Highlighter you use always gives me just one long line of code. Here's an image. I'm sure the issue is at my end, but I was wondering if you have any suggestions as to what I might try to fix this.
Tuesday, August 23, 2011 9:38:35 PM UTC
cwindhausen - Try Ctrl-F5 to clear your cache? I'm on Chrome 15 and I only see that with really long singe lines where the code is actually setup that way.
Tuesday, August 23, 2011 9:38:59 PM UTC
Loooooooooooove the preview feature. Makes an already great feature even better!!
Tuesday, August 23, 2011 11:34:00 PM UTC
A side step - why do people still use appSettings as in Scott's example? applicationSettings is the way to go AFAIK.
Wednesday, August 24, 2011 2:09:40 AM UTC
I am getting some weird behavior with this plugin. I created a new configuration called Home. I added, via the popup menu, a new transform and it did add Web.Home.config to my project. I altered the database connections to point to me DB here at home - and yes, I tested them. When I hit F5 I get a "cannot find DB" error. I also made sure the Home configuration was selected.

Next, I copy the connection strings to my base web.config (debug does not have any transforms!) and select the Debug configuration then hit F5 it runs just fine.

What am I missing? Only Release and Debug seem to work as you said.
Wednesday, August 24, 2011 2:26:31 AM UTC
This is cool. It's a hairy problem to solve.

One alternative we tried at work was to use a web.master.config file and just use {replacementTags} and then a companion web.values.ini file using a common [configProfileSectionName] and Name=value pairs. With that and tiny, smart little search and replace console app called in a post-build action, we've had far fewer configuration errors with multiple dev, QA, UAT and production environments. Each environment gets it's own [section] and Name=value pairs. Those go into source control and allow changes to be tracked, blamed and otherwise better managed.

So far it's worked well.
Wednesday, August 24, 2011 2:28:12 AM UTC
Oh, I forgot to mention. One problem with that is that the web.config file has to be there in order for the project to compile. So we added back in a non-versioned copy of the file. Bing, bang, boom. Compiles and deploys nicely.
Wednesday, August 24, 2011 4:49:41 AM UTC
Hi Keith, when you are creating your new configuration are you checking the check box "Create new projec configurations"? In order for these transforms to work you have to create a project configuraiton, not just a solution configuration. If you are still having issues please email me at sayedha[at]{Microsoft}(dotCOM).
Wednesday, August 24, 2011 5:38:48 AM UTC
Hi Scott. One smaill issue - this doesn't appear to work for a ClickOnce deployment (WPF app). Am I missing anything?
Wednesday, August 24, 2011 10:42:26 AM UTC
Folks want to transform their app.configs, or any XML file as part of their builds. Additionally, the current system only runs the transforms as a part of the publish process and folks would rather the transform happen "on F5" or on build. So, my team members Sayed Ibrahim Hashimi and Chuck England have done just that as a small VSiX called SlowCheetah XML Transforms.

Ha! I was just looking for that this morning! It will make it much easier to commit a project to github without the sensible information of the connectionstring for example.
1. Add the connectionstring to the Web.debug.config
2. Add Web.debug.config to the .gitignore
3. ...
4. Profit

Thanks Scott :)
Wednesday, August 24, 2011 2:34:08 PM UTC
Erf, in fact, it does not work out of the box for web projects...
See details about a solution here :
http://sedodream.com/CommentView,guid,68b7e248-b9f5-4d07-bdfe-eb037bcf2cbb.aspx#commentstart
Wednesday, August 24, 2011 7:15:16 PM UTC
Just for comparison, here's an XSLT 3.0 stylesheet that does the same job as the XSLT 1.0 sample

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:mode on-no-match="copy"/>
<xsl:template match="configuration/appSettings">
<xsl:apply-templates/>
<add key="NewSetting" value="New Setting Value"/>
</xsl:template>
</xsl:stylesheet>


XSLT 3.0 isn't a W3C recommendation yet, but this works fine in the latest version of Saxon.NET with XsltLanguageVersion set to "3"
Wednesday, August 24, 2011 9:21:09 PM UTC
This tightens it up a little bit,

<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:if test="parent::appSettings/parent::configuration">
<!-- add new settings here-->
<add key="NewSetting" value="New Setting Value"/>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>



But you don't typically write an entire c# program from scratch in a single module, and likewise for xslt. If your going to do this sort of stuff more than once, and do more than just add keys, you can factor out the common stuff into a "library" as you would in a c# program. XSLT is happy to be modular and even do inheritance like c#. Here an example just to show this sort of thing can be done.

This is the "library" module, modConfig.xsl

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:mods ="config:mods">
<xsl:output indent="yes"/>
<xsl:variable name ="mods:mods"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/configuration/appSettings/add">
<xsl:if test="not($mods:mods/mods:remove/*/@name != @name)">
<!-- this is a remove, skip it-->
</xsl:if>
<xsl:if test="not($mods:mods/xsl:stylesheet/mods:replace/*/@name != @name)">
<!-- this is a replace, we will add it later-->
</xsl:if>
</xsl:template>
<xsl:template match="/configuration/appSettings">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<xsl:copy-of select="$mods:mods/mods:add/add"/>
<xsl:copy-of select="$mods:mods/mods:replace-or-add/add"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>


And this is and example file that would define some modifications you would want to make to a config file.

mymods.xsl

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:mods ="config:mods">
<xsl:import href="modConfig.xsl"/>
<xsl:variable name="mods:mods" select ="document('')/xsl:stylesheet"/>
<mods:add>
<!-- add new app settings here-->
<add key="NewSetting" value="New Setting Value" />
</mods:add>
<mods:replace-or-add>
<!-- add replace or add settings here-->
<add key="NewSetting2" value="New Setting Value2" />
</mods:replace-or-add>
<mods:remove>
<!-- add remove settings here-->
<add key="NewSetting3" />
</mods:remove>
</xsl:stylesheet>


It's got a little boiler plate, but there are parts for adds, replacements, and removes.

and here is an example file to apply the transform to:

app.config
<configuration>
<appSettings>
<add key="test" value ="7"/>
<add key="NewSetting3" value ="8"/>
</appSettings>
</configuration>



<configuration>
<appSettings>
<add key="NewSetting" value="New Setting Value" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mods="config:mods" />
<add key="NewSetting2" value="New Setting Value2" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mods="config:mods"/>
</appSettings>
</configuration>


Of course this is just an off the top of the head example. modConfig.xsl is a bit involved, but you write that once and then reuse it, as you would any library. With a better understanding of the req's mymods.xsl file could be simplified more or enhanced for other req's. But by using XSLT you don't really need anything "new".

Wednesday, August 24, 2011 9:30:10 PM UTC
RE:ClickOnce support
I looked at the ClickOnce issue and I think I might have something that works. Can you download the file contents from http://pastebin​.com/hjhcgHsB and update the file C:\Users\{YOURU​SERNAME}\AppDat​a\Local\Microso​ft\MSBuild\Slow​Cheetah\v1\Slow​Cheetah.Transfo​rms.targets Then make sure to close all your instances of VS. If it works I'll integrate these changes into the plug in.
Thursday, August 25, 2011 6:59:25 AM UTC
This is all cool, but in the case of deployment I feel like building seperate packages for each environment seems kindda wrong. For instance I typically wanna do some testing on a QA environment, before deploying onto a production environment. Transformations requires me to built a package for each environment, hence I need to be 100% sure that each build is based on the same baseline. I would rather base my QA and prod installation on the same package.

I have started using parametrization instead which allows me to have a parameters.xml per project, and a setParameters.xml for each environment. This way I can just pass the setParameters.xml which holds configurations for the target environment when I deploy my application via msdeploy, enabling me to use the same deployment package.

I would love to see a blog post on msdeploy and parametrization Scott, since quality info on the subject seems kindda rare.
Friday, August 26, 2011 1:33:14 PM UTC
Nice article. I really love webconfig transformation. especially for deploying,
Thanks
Friday, August 26, 2011 1:47:52 PM UTC
Will this be bundled with the next version of the framework? Copying SlowCheetah files over to the build server is kinda klunky. Checking them in to source control is a slightly better approach.

Linking to http://msdn.microsoft.com/en-us/library/dd465326.aspx in the body of the article might be useful.

Does anyone know if there's a MSBuild equivalent to NAnt's Filter Chains for creating template files and filling the template with values from properties files (one property file per tier: dev, test, & prod)?

I think a templating approach would have a shorter learning curve. Most folks are going to be more familiar with a templating approach than with XSL or XDT (especially if they don't have a web background). After all, isn't ASP.NET just one big templating engine anyway? I haven't confirmed it, but my suspicion is that a templating (vs transforming) approach would be less verbose as well.

P.S. Typo: "The ShowCheetah XML Transform Add-In…" should be "The SlowCheetah…"
Robert Stackhouse
Friday, August 26, 2011 2:00:02 PM UTC
After installing the VS extension and adding a transform, I right-clicked my App.Debug.config and selected "Preview Transform". That's when I was greeted with the message, "Transform assembly not found."
Robert Stackhouse
Friday, August 26, 2011 2:09:44 PM UTC
Some help with this would be good.


Error 11 The imported project "<Profile Directory>\Local Settings\Application Data\Microsoft\MSBuild\SlowCheetah\v1\SlowCheetah.Transforms.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk…
Robert Stackhouse
Friday, August 26, 2011 3:38:14 PM UTC
Looks like my issue was XP specific (I would upgrade OSes if I could, but I don't control the purse strings).

Adding a system environment variable named LOCALAPPDATA with the value "%USERPROFILE%\Application Data" fixed it. This comes from http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5/view/Discussions under the Q&A tab.
Friday, August 26, 2011 4:40:20 PM UTC
Hi Robert, as you noticed on the forums there are issues with XP. I didn't realize that the env var LocalAppData is not available in XP. It sounds like your issues are resolved, but if not plese email me directly. You can find my email on the discussions tab of the add in within the comments.

Thanks,
Sayed Ibrahim Hashimi
Friday, August 26, 2011 6:42:56 PM UTC
It should probably be noted that for anyone who is copying an App.config file over for integration testing purposes using MSTest, that the transformations don't get applied.

What your test setup requires should be in your App.config. Put prod settings in App.Release.config.
Thursday, September 01, 2011 7:07:07 PM UTC
Do I need to do additional change so different configurations work in TFS? Even though I have different app.configs the same config file is copied, in this case debug, when I run the build.
Richard Valdivieso
Friday, September 02, 2011 4:01:51 AM UTC
Hi Richard, all the transform logic is captured in MSBuild files so getting TFS support is pretty simple. Follow these steps:
1. From a machine which has SlowCheetah installed copy the files from %LOCALAPPDATA%\​Microsoft\MSBui​ld\SlowCheetah\​v1\
2. Check the files into TFS
3. In your build definition specify the property SlowCheetahTargets to be the path to the SlowCheetah.Transforms.targets file

That should be it.

Sayed Ibrahim Hashimi
Friday, September 02, 2011 9:36:49 PM UTC
Thank you so much for your quick answer. Maybe this is a basic question, but how I can reference SlowCheetah.Transforms.targets? I know that property is inside of the project file, but every time that I build it creates a new version (1,2,3) so the file has different location. Also, when I use the build in team foundation all the files end with deploy extension, so I do not know how to add the path. Do you have a basic hello world kind of thing as example. Thanks again for your anwers.
Richard Valdivieso
Tuesday, September 06, 2011 6:44:41 PM UTC
This is my output from my little example. I notice that the transformation occured in the build folder and the buildOutput folder. But I notice that on _CopyFilesToPublisher folder is failing. Here is the log file:
*******************************************************
TransformAllFiles:
Transforming Source File: C:\Builds\1\Training\TestWindowsApp_TFSDemo\Sources\TestWindowsApp_TFSDemo\TestWindowsApp_TFSDemo\app.config
Applying Transform File: app.UAT.config
Output File: C:\Builds\1\Training\TestWindowsApp_TFSDemo\Binaries\TestWindowsApp_TFSDemo.exe.config
Transformation succeeded
_CopyFilesToPublishFolder:
Creating directory "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18".
Copying file from "C:\Builds\1\Training\TestWindowsApp_TFSDemo\Binaries\TestWindowsApp_TFSDemo.exe.manifest" to "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\TestWindowsApp_TFSDemo.exe.manifest".
Copying file from "obj\UAT\TestWindowsApp_TFSDemo.exe" to "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\TestWindowsApp_TFSDemo.exe".
Creating directory "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\Assemblies".
Copying file from "Assemblies\ClassDemo.dll" to "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\Assemblies\ClassDemo.dll".
Creating directory "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\SlowCheetah".
Copying file from "SlowCheetah\Install-Manifest.xml" to "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\SlowCheetah\Install-Manifest.xml".
Copying file from "SlowCheetah\SlowCheetah.Tasks.dll" to "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\SlowCheetah\SlowCheetah.Tasks.dll".
Copying file from "SlowCheetah\SlowCheetah.Transforms.targets" to "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\SlowCheetah\SlowCheetah.Transforms.targets".
Copying file from "app.config" to "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\TestWindowsApp_TFSDemo.exe.config".
Copying file from "C:\Builds\1\Training\TestWindowsApp_TFSDemo\Sources\TestWindowsApp_TFSDemo\TestWindowsApp_TFSDemo\Assemblies\ClassDemo.dll" to "\\tfs1\Deployments\Publish\TestWindowsApp_TFSDemo\Application Files\TestWindowsApp_TFSDemo_1_0_0_18\ClassDemo.dll".
Done Building Project "C:\Builds\1\Training\TestWindowsApp_TFSDemo\Sources\TestWindowsApp_TFSDemo\TestWindowsApp_TFSDemo\TestWindowsApp_TFSDemo.vbproj" (Publish target(s)).
Project "C:\Builds\1\Training\TestWindowsApp_TFSDemo\Sources\TestWindowsApp_TFSDemo\TestWindowsApp_TFSDemo.sln" (1) is building "C:\Builds\1\Training\TestWindowsApp_TFSDemo\Sources\TestWindowsApp_TFSDemo\ClassDemo\ClassDemo.vbproj" (3) on node 1 (Publish target(s)).
_DeploymentUnpublishable:
Skipping unpublishable project.
Done Building Project "C:\Builds\1\Training\TestWindowsApp_TFSDemo\Sources\TestWindowsApp_TFSDemo\ClassDemo\ClassDemo.vbproj" (Publish target(s)).
Done Building Project "C:\Builds\1\Training\TestWindowsApp_TFSDemo\Sources\TestWindowsApp_TFSDemo\TestWindowsApp_TFSDemo.sln" (Publish target(s)).

Build succeeded.
Richard Valdivieso
Wednesday, September 07, 2011 7:17:31 PM UTC
Apparently the Extension Manager is downloading a old version or a version without ClickOnce code. Our team find your code with the click once at
http://pastebin.com/hjhcgHsB#
Richard Valdivieso
Thursday, September 08, 2011 4:05:16 AM UTC
The extension hasn't been updated to include the ClickOnce support yet. That will be in the next release, after we can implement a few other features :)
Thursday, September 08, 2011 4:06:50 AM UTC
Regarding your question:

Thank you so much for your quick answer. Maybe this is a basic question, but how I can reference SlowCheetah.Transforms.targets? I know that property is inside of the project file, but every time that I build it creates a new version (1,2,3) so the file has different location. Also, when I use the build in team foundation all the files end with deploy extension, so I do not know how to add the path. Do you have a basic hello world kind of thing as example. Thanks again for your anwers.


Just check in the files and then specify the path relative to the project directory. For example something like: "..\..\..\..\SlowCheetahIsAwesome\"
Thursday, September 08, 2011 11:41:10 AM UTC
I've tried using SlowCheetah for adding transformations for an xml file in my webproject (crossdomain.xml) and I've tried it to add transformations for a ServiceReferences.clientconfig in my Silverlight project. Unfortunately it doesn't seem to work. Is it necessary to do something specific to support that? It now only seems to support changing an app.config.
Thursday, September 08, 2011 11:54:53 AM UTC
This is so weird then. I make it work with the additional target that is at http://pastebin.com/hjhcgHsB#
I record all my steps in 3 rough videos. These videos are aroun 20 Mb each. All the steps I did make it work. Of course chances are that I am doing this the wrong way.
Thanks agains.
PD: It you want to see these videos let me know at @richvaldivieso.
Richard Valdivieso
Friday, September 09, 2011 4:18:18 PM UTC
Why does this have to work only via transforms. What if I just want to SPECIFY my production config as opposed to having to effectively write a program describing how to get to a production config from a dev config.

Seems like needless pain to me. Where's the love here?
Friday, September 09, 2011 4:28:31 PM UTC
btw... when VS 2010 came out, I quickly requested a feature supporting multiple config files matched to configurations by name convention.

EG: web.Debug.config , web.Release.config etc.
Tuesday, September 13, 2011 3:39:52 AM UTC
@Eric, if you want to do a full replacement just put the xdt:Transform="Replace" on the root element. For example:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xdt:Transform="Replace">
<appSettings>
<add key="appName" value="WPF Demo-Debug" />
<add key="url" value="http://localhost:8080/"/>
<add key="email" value="debug@contoso.com"/>
</appSettings>
<system.web>
<anonymousIdentification cookieless ="AutoDetect"/>
</system.web>
<connectionStrings>
<add name="RecordsDb" connectionString=".\SQLExpress;Initial Catalog=RecordsDb;Integrated Security=true"/>
</connectionStrings>
</configuration>
Tuesday, September 13, 2011 6:04:52 PM UTC
Great!!! Just what i need, thanks!!
Friday, September 23, 2011 1:37:14 PM UTC
Hi,

How can we add the xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0" attribute to the <configuration> element in a xml transformation?

original: <configuration>
target: <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">

Anybody an idea?

Sander Bouwmeester
Friday, October 07, 2011 12:26:33 AM UTC
Just what was needed. Thanks, Scott / Sayed / Chuck.
Rakesh
Friday, October 21, 2011 12:08:33 AM UTC
Wasn't this available already? I've been using this task for a while.

    <UsingTask
TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
...
<TransformXml
Source="$(SourceDirectory)\Example\App.config"
Transform="$(ConfigDirectory)\$(SolutionName).Example\App.$(DeploymentEnvironment).config"
Destination="$(PredeployDirectory)\$(SolutionName).Example\$(SolutionName).Example.exe.config" />

Friday, November 11, 2011 10:20:28 PM UTC
Hi

What about a transformation for all .config files in an VS solution with severals projects within ?


Monday, January 23, 2012 8:27:00 PM UTC
Is it possible to use Microsoft's XML document transform outside of MSBuild? I would like to use PowerShell to do these transform without having to run this through the MSBuild engine.
Thanks
Thursday, January 26, 2012 3:36:01 PM UTC
At the beginning I though this feature was useful but then I noticed that it isn't so useful. The config file is transformed only when you DEPLOY the project, but when you start the application from VS the config file is always the same!
It would have been better to have a web.config.template and a generated web.config in the solution.
Spamme
Friday, January 27, 2012 1:50:00 PM UTC
@What Would Be Cool, I'm doing transforms through PowerShell using the MSBuild task similar to how http://ctt.codeplex.com/ does it. You could also call the executable from PowerShell.
Thursday, March 01, 2012 4:38:57 PM UTC
I love this extension and have been using it for a while however I am unable to get the transforms to run when publishing a wcf service. It works if I do a normal build, but then the configs go into the bin folder, and are not part of the publish.

Can anyone help? My initial searches on the internet have produced no results.
Thursday, March 01, 2012 5:12:58 PM UTC
Hi Tim, thanks for your feedback. It looks like the WCF publish dialog is picking up the app.config from the source path instead of the output folder.
I have placed this item on the backlog. I will try and get this in for the next version.

Thanks,
Sayed Ibrahim Hashimi
Wednesday, March 07, 2012 1:20:57 PM UTC
Super cool - have been looking for this for an long time. Will it be on NuGET at any time in the future?
Christian Franck
Thursday, March 29, 2012 5:39:40 PM UTC
This is awesome, saved me two days of work. Thanks guys.
Esen
Friday, April 13, 2012 9:20:36 AM UTC
<!-- Web.Config Configuration File -->

<configuration>
<system.web>
<customErrors mode="Off"/>
</system.web>
</configuration>



<!-- Web.Config Configuration File -->

<configuration>
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="mycustompage.htm"/>
</system.web>
</configuration>
Ravinder Prasad
Friday, April 13, 2012 9:21:39 AM UTC
plz. send in my e mail id thank u
Ravinder Prasad
Thursday, April 19, 2012 12:33:27 PM UTC
Is it possible to use XDT inside C# projects? How?

I have XMLs in database that need to transform updating values, simple changes, depending on certain conditions and show to the customer.

XDT seems ideal, simpler than XSLT but how can I use it inside my C# project?

Thanks

Sunday, September 23, 2012 2:15:23 PM UTC
This add-on seemed very promising in the beginning but I've run into a serious problem with it.

Let's say I've got project Inner and two projects which are referencing it Outer1 and Outer2. Inner contains the xml file I want to tweak according to configuration. I also want both deployment directories to contain that xml file. Pretty standard, right? Only it doesn't work. Turns out that the only output directory in which the xml file is tweaked is Inner's output directory. Both Outer projects have the original xml file in their output directories.

I could of course change Inner's output directory to one of the Output directories but then the other one would still have the original file.

Has anyone encountered this problem before?
Lena
Monday, September 24, 2012 12:30:54 AM UTC
Sayed, the author says: "Lena, thanks for letting me know about this. I looked into it and you are absolutely right the transform is not making it to the referenced project's directory. I've opened an issue to track this at https://github.com/sayedihashimi/slow-cheetah/issues/34. You can subscribe to the issue there if you are interested in updates. Thanks!"
Tuesday, October 16, 2012 11:47:08 AM UTC
Hi,

This is great; however I must ask whether it is limited to two configurations of the base config... i.e. Debug & Release? Let's say that a particular component gets deployed in a multiple of environments and that the component to function in those environments would require different varying environmental settings. Can this be achieved using transformations? It would seem like it should be achievable with this mechanism..
Dave Lawrence
Wednesday, December 19, 2012 9:49:52 AM UTC
good, from now on, app.config also can use config transforms.
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.