Big picture thoughts on software and other topics

June 11, 2007

Nant Task for Creating IIS Application Mappings

by Brian Donahue

Update 10/2/2008 - I finally got around to posting the source and binaries on Google Code:
https://code.google.com/archive/p/nant-iisappmap/

Update
-- Billy McCafferty has posted another way to add Extension Mappings to IIS via NantBroken Link: http://devlicio.us/blogs/billy_mccafferty/archive/2007/07/13/configuring-iis-for-monorail-with-nant.aspx.  Definitely effective, but I still think mine is easier and cleaner - keeps all that script mess out of your beautiful build script. 

We've been working on our continuous integration here, setting up CruiseControl.NETBroken Link: http://ccnet.thoughtworks.com/ and cleaning up/improving our Nant build scripts.  Jean-Paul BoodhooBroken Link: http://www.jpboodhoo.com/'s series on Automating Your Builds with Nant has been an invaluable resource of great ideas and best practices (pretty much every post on his blog fits that description). 

Some of Jean-Paul's examples include pre-compiling and deployment of ASP.NET apps.  He uses the mkiisdir task in the Nant.Contrib library to create virtual directories via Nant.  One issue we were having was that several of our applications make use of additional application mappings in IIS for custom HTTPHandlers.  So the deployment task we had in our builds was only getting us part of the way there, and then we would have to add these mappings in manuallyBroken Link: http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/4c840252-fab7-427e-a197-7facb6649106.mspx?mfr=true to get our application to work completely.  Application mappings are also known as extension mappings or script mappings, but basically it amounts to mapping a file type (.jpg, .rails, .myextension) to a handler, usually the aspnet_isapi.dll if you are writing a custom HttpHandler.

At first I thought there must be a way to do this with the mkiisdir task, but it was not to be.  So, I decided to try to make my own Nant task to do so.  New to scripting IIS configuration, I turned to google.  After finding a few near-miss examples and discussions, I discovered the "ScriptMapsBroken Link: http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/45e717d0-20f6-459c-9183-cf6019f2edab.mspx?mfr=true" property Broken Link: http://www.microsoft.com/windows/windows2000/en/server/iis/htm/asp/apro9tkj.htmof the IIS MetabaseBroken Link: http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/43a51d34-7c81-413b-9727-ec9a19d0b428.mspx?mfr=true.  Another useful tool was the ability to export your IIS settings to XML with IIS 6 - this basically serializes out the IIS Metabase settings for a website via the IIS management console.  You can then view them and get a feel for what you need to do to create a similar site. 

I started coding my task from scratch, when it dawned on me that Nant and NantContrib were open source projects, and why the heck wasn't I looking at the mkiisdir code for a good example of tinkering with the IIS Metabase!?  So, off I went to download the source, and noticed a very useful base task called "WebBase" in Nant.Contrib.Tasks.Web.  This task allowed me to use some of the same attributes as the mkiisdir task, and handled some of the communication with the IIS Metabase.  I added a few attributes to create the mapping string, and added the string to the "ScriptMaps" property collection.

The task call in your build script will look something like this:

<iisappmap vdirname="MLDB.Website"
extension=".jpg"
executable="C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll"
verbs="GET,POST"
checkfileexists="false" />

The code can be found here (with comments describing usage) and the binary here.  To use in your builds, you will need to add to the appropriate area in your Nant bin directory - older versions just use <Nant>\bin\tasks I believe the latest uses <Nant>\bin\tasks\net

I tested this in IIS 6 and 7.  In IIS 7 it adds the mapping, but it adds it as an "Internal" mapping as opposed to the new "Local" mappings IIS 7 uses by default.  It caused no problems for me, but if you wanted the mapping to be added to your web.config, the way IIS 7's management tool does, this task will not do that for you.  Of course, if you put it in your web.config, you don't need this task!  Just deploy your web.config with your app :)

P.S.  I don't know much about open source etiquette, but seeing as this builds on top of NantContrib, I'd be happy to contribute it to that library if people find it useful.  I'm sure others will find ways to improve it, too!