Scott Hanselman

XmlPreprocess is an elegant hack - or - "The hack is in the eye of the beholder"

December 16, 2004 Comment on this post [6] Posted in ASP.NET | XML | Bugs
Sponsored By

Hack? Brilliance? Sloppy? Simple? Here's when I know something is good:

  • It's easily explained.
  • It's not ambiguous.
  • There aren't many files.
  • Self-containment.
  • It's simple

Seeing a pattern? Loren has come up with an interesting and elegant hack called XmlPreprocess to deal with the deployment of config files to multiple environments without the need for multiple copies. It would be EASILY integrated into a Continuous Integration environment like ours.

The idea is bone simple:

<configuration>
<system.web>
<!-- ifdef ${production} -->
<!-- <compilation defaultLanguage="c#" debug="false"/> -->
<!-- else -->
<compilation defaultLanguage="c#" debug="true"/>
<!-- endif -->
</system.web>
</configuration>

gets loaded into "XmlPreprocess.exe /d production" and you get:

<configuration>
<system.web>
<compilation defaultLanguage="c#" debug="false"/>
</system.web>
</configuration>

Cool, eh? Now, some may thing preprocessor/if statements "tunneled" in XML Comments are gross, but to the nay-sayers I say show me one man's extensibility hack and I'll show you xs:annotation. Would you feel better if the "language" was hidden in other XML elements? Or another namespace? Sure, it's possible, but the goal isn't a new language (if statement = new language) it's #ifdef for XML for a specific purpose.

Reasons it's cool:

  • The files are well-formed and legit XML before and after the process. No processing is needed to use them as found in Source Control.
  • The files are self-describing. Just look at them, it's clear what's up.
  • As Loren says, Get and Go.

Charlie says in comments on Jon Galloway's blog that it's a hack that this is "definitely not the way most natural way of dealing with XML" and he'd prefer XSLT. He does point out that XSLT isn't for newbies. However, for this small task I say, Wow, no way.

Using XSLT to change a config file in such a small way seems like hammering a screw. It's possible, but overkill that WILL get messy. Look at the previous requirements and apply XSLT. XSLT is great for transforming Infosets into other totally different Infosets, and while I'm deep into XSLT, I'm not a fan of using XSLT for small "pruning" changes.

I think XmlPreprocess is clever thing that's good for exactly what it's good for. Check it out!

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 bluesky subscribe
About   Newsletter
Hosting By
Hosted on Linux using .NET in an Azure App Service
December 16, 2004 15:30
Reminds me of my mixed reactions at the thought of pre-processing C# source: http://blogs.geekdojo.net/pdbartlett/archive/2004/02/23/1191.aspx
December 17, 2004 7:46
NAnt has two tasks that might be useful for this kind of automation:
xmlpeek and xmlpoke

Using these, you can use a standard NAnt build file to differentiate between deployment options, for example by having a target for each scenario, each containing xmlpoke instructions for just those settings that need to be changed relative to the "master" web.config file.

web.config:
Defines the structure, and default values.

build.xml:
Defines one target for each deployment scenario (prod, dev, staging, etc).
Each target creates a web.config for deployment, calling a series of xmlpoke commands as needed to override the master, modifying the web.config as appropriate.

For example, to build a distribution for the "staging" server (and maybe even deploy it to the staging server), you'd run "NAnt staging" (if you created a "staging" target), or perhaps "NAnt -D:config=staging" if your script will consider the "config" property to determine which appropriate configuration task to run.

If you are already using NAnt to do the deployment (even just zipping up the source for FTP), creating an should automate the config customization step.

The benefits (in my opinion):
1. Deployment configuration details are stored alongside any other deployment instructions already in the build script.
2. The web.config is more "clean" than when it must contain the alternative configuration values for all deployment scenarios as comments.
Its size and readability scale per the configuration, not per the number of deployment scenarios.
3. Scalability: If the configurations for each deployment scenario diverge significantly, you have a number of different options for structuring your build files. You can have conditional processing based on a property, or one target for each scenario, or even one build file for each scenario, depending on your needs and preferences.
December 17, 2004 11:06
Did you see what I was proposing for a natively supported environment aware web.config in the second half of my post (http://weblogs.asp.net/jgalloway/archive/2004/12/15/309902.aspx)?

Not necessarily the right way to implement it, but I think the basic functionality would be nice. I really like the "Get and Go" principal and would like it if the web.config parser could obviate the need for a command line add on.
December 18, 2004 19:57
Actually XML has a dedicated syntax for expressing processing instructions - XML processing instructions. There would be no need for such hacks if XML processing instructions were allowed in standard sections of .NET config files, but they aren't allowed.
My take on XmlPreprocess - http://www.tkachenko.com/blog/archives/000368.html
December 22, 2004 10:30
I'm with Ben. I use the XML tasks in NAnt to modify configuration files for deployment. XmlPreprocess is not clever or cool. This is a stupid hack for the NAnt illiterate. I am surprised to see Scott recommend such nonsense!

Say it ain't so Scott. Read this http://nant.sourceforge.net/help/tasks/xmlpoke.html and then take your statements back!
December 22, 2004 22:28
I surprised you guys feel so strongly about this (especially Anonymous, who didn't leave a name! :) )

Of course I have used XmlPeek and XmlPoke with NAnt. However, this is a clever hack because of the reasons I outlined - the most interesting one being that it's self-contained. Oleg makes good points about XML PIs, but as he, we all know, .NET config files don't allow PIs. If PIs were used, it'd have been an even more clever hack.

"A stupid hack for the Nant illiterate?" Hardly. It's a simple hack for folks who don't want:

* Another whole app and all the dlls (NAnt)
* Another whole XML language (NAnt + XPath)
* Another whole file (the NAnt build file)

Comments are closed.

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