QUICK SUMMARY: Below you will find a sample .vbs script that demonstrates how to add a custom ScriptMapping to IIS to allow ASP.NET applications to handle ’static’ file extensions like .xls
I had an odd requirement to fulfill at my day job today, and as so frequently happens with odd requirements, it took WAY too long to find the relevant information on the Internet, so I’d like to post this quick code snippet in hopes that the next person to encounter such a task may find something relevant in Google with perhaps less effort than I needed to spend.
Basically, I am working on an ASP.NET web application which allows the user to view reports in several different formats: PDF, Word, Excel, RTF, etc, etc. The reports are generated via an ASP.NET page, which uses Crystal Reports on the server-side to generate the actual report in the proper format, which is then passed back to the browser.
The problem is that with formats like Word and Excel, which can potentially contain user macros (scripts) and could possibly pose a security risk when downloaded from an untrusted source, clients will often pop up ominous-sounding warnings when the URL that was requested does not seem to match the type of data that was returned (click to bigify) :
It’s important to note that this happens even when using Content-Disposition headers to specify that the report should be handled as an attachment of the appropriate type, and is in addition to the annoying "Open / Save / Cancel " dialog :
One solution is to use URL rewriting to make the request match the file type, and allow ASP.NET to handle requests for file types it does not normally handle, in this case .xls files, and configuring IIS to pass such requests to the ASP.NET engine for processing. In other words, if you can make the report URL look something like this http://server/reports/assets-by-model.xls, the browser is not surprised when it gets an Excel file in return.
In my case, this also meant that I had to automate the process of adding the custom mapping during the install process. Fortunately for me, we use NSIS for our installer, so generating and spawning a VBS script to handle the task is a fairly simple matter.
The example script is below. A word of caution : I’ve been up for more than 24 hours, working my ass off to meet a deadline with a client, so I make no warranties as to the quality of the code. The only thing I can say about it at this point is that it seemed to serve my needs when I posted it here, and that I sincerely hope it’s helpful to someone else out there
' This example VBS script adds an IIS script mapping to allow ASP.NET ' to process .xls file requests as if they were .aspx pages. This ' is useful when using URL rewriting to implement "export as Excel" ' functionality, where the browser will complain if the requested ' URL file extension doesn't match the MIME type. ' ' NOTE: This script assumes that you are not using the root web directory, ' but rather a subdirectory like http://myserver/myvirtualdir ' on error resume next strVDirName = "MyVirtualDir" strCustomExtension = ".xls" set objW3SVC = GetObject ("IIS://localhost/w3svc") set objWebSite = objW3SVC.GetObject( "IIsWebServer", 1 ) set objDefaultWebsite = objWebSite.GetObject("IIsWebVirtualDir", "root") set objVDir = objDefaultWebsite.GetObject("IIsWebVirtualDir", strVDirName) if isempty(objVDir) then WScript.Echo "Failed to configure " + strVDirName + " for " + strCustomExtension + " files." + vbCRLF + "The virtual directory could not be found." WScript.Quit(UNKNOWN_PARAM) end if list = objVDir.ScriptMaps strDotNetScriptMapping = "" strCustomScriptMapping = "" for i = 1 to ubound(list) if( left(list(i),5) = ".aspx" ) then strDotNetScriptMapping = list(i) else if( left(list(i),len(strCustomExtension)) = strCustomExtension ) then strCustomScriptMapping = list(i) end if end if next if strCustomScriptMapping <> "" then WScript.Echo "This virtual directory is already configured for " + strCustomExtension + " files." else if strDotNetScriptMapping = "" then WScript.Echo strVDirName + " is not properly configured for ASP.NET" else strCustomScriptMapping = replace( strDotNetScriptMapping, ".aspx", strCustomExtension ) i = ubound(list) + 1 redim preserve list(i) list(i)= strCustomScriptMapping objVDir.Put "scriptmaps", (list) objVDir.SetInfo end if end if