Tuesday, July 22, 2008

Recently I had to make an .mdb file accessible for download after authentication and couldn't allow a direct link to the file. We had written a similar handler for .xls and others (.csv, etc...) - we sent back a few headers to set the file name and the mime type and then server.transfer'd to stream out the binary file.

Turns out that IIS maps .mdb files to the aspnet_isapi.dll executable by default (in fact on the server we were testing it was also mapped to a perl interpreter... go figure) , making server.transfer cough. We were receiving the following error when trying to do the transfer:

System.Web.HttpException: Error executing child request for /{ourdirectory}/{ourfilename}.mdb

[HttpException (0x80004005): Error executing child request for /{ourdirectory}/{ourfilename}.]
   System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride) +2672379
   System.Web.HttpServerUtility.Execute(String path, TextWriter writer, Boolean preserveForm) +819
   System.Web.HttpServerUtility.Transfer(String path, Boolean preserveForm) +57
   System.Web.HttpServerUtility.Transfer(String path) +35
   {mycontrol}.Page_Load(Object sender, EventArgs e) in {path to my control file}.cs:33
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +99
   System.Web.UI.Control.LoadRecursive() +50
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627

One of the options that we found was to simply remove the mapping in IIS, but then I ran into the problem of not being able to remove the mapping from the ASP.NET Development Server (at least in a way I could figure out easily). So, option 2 presented itself and we found it to be the best solution for both situations. Simply add the following in the <httpHandlers> section of your web.config:

<remove verb="*" path="*.mdb" />

If you don't have an httpHandlers section of your web.config, it goes in as a subsection of <system.web>

<system.web>
<!-- ... other stuff .. -->
<httpHandlers>
<remove verb="*" path="*.mdb" />
</httpHandlers>
<!-- ... other stuff ... -->
</system.web>

No more problems with code like the following:

Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=" + myFileName);
Response.Flush();
Server.Transfer(baseVirtualPath + myFileName);

No my dev environment using Asp.Net Development Server had the same settings that the IIS 6 app had, so I could test and debug properly.

Some helpful links that helped me solve the problem:

http://www.eggheadcafe.com/software/aspnet/29460604/iis-6-wont-serve-mdb-fil.aspx
http://forums.asp.net/p/1022569/1393806.aspx