Thursday, July 9, 2009

Allow MSI Downloads on ASP.NET Web Site

I can't tell you how many hours I spent over the last few weeks trying to debug a problem with a web site where we were trying to allow users to download an MSI from a blob. Sometimes it would work the first time, and then the next time, the site would try to download the .aspx file the code was running in.

What made it really confusing was that this problem only happened when we were running in Azure with IE 8. In IIS 7 running on Win2K8, it was fine. With Azure and FireFox, it was fine. At one point, we had it working on everything except IE 8 running on Windows 7 with a backend of Azure.

What I finally had to do, was to create an ASP.NET Generic Handler (ashx) that did the heavy lifting for me.  To give credit where credit is due, the suggestion came from someone I met while at the latest NerdDinner in Bellevue, WA on July 7.  (I wish I could give you his name, but I do know he was on the ADO.NET Services Team at Microsoft)   This is the second time that I have attended one of those dinners, and the second time I was able to solve a problem the next day based on advice given to me by someone there.   Many thanks to Scott Hanselman for getting these events put together.

Here was the final code:

public class MsiDownload : IHttpHandler



{



    protected readonly ILog _log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);



 



    public void ProcessRequest(HttpContext context)



    {



        string msiName = ConfigurationManager.AppSettings.Get("MSIName");



        byte[] returnedBytes = null;



 



        var blobManager = UnityFactory.Current.Resolve<IBlobManager>();



 



        try



        {



            returnedBytes = blobManager.GetMsi(msiName);



            if (returnedBytes == null)



            {



                _log.ErrorFormat("Error obtaining MSI from blob storage service. Returned bytes is zero length.");



            }



        }



        catch (Exception exc)



        {



            _log.ErrorFormat("Error obtaining MSI from blob storage service. Exception type: {0}, Exception Message {1}.", exc.GetType().ToString(), exc.Message);



        }



 



        if (returnedBytes != null)



        {



 



            context.Response.Buffer = true;



            



            // force download



            context.Response.ContentType = "application/x-msi;";



            context.Response.AppendHeader("X-Content-Type-Options", "nosniff");



            context.Response.AppendHeader("content-disposition", "attachment; filename=" + msiName);



            context.Response.AppendHeader("Content-Length", returnedBytes.Count().ToString());



            context.Response.OutputStream.Write(returnedBytes, 0, returnedBytes.Count());



            context.Response.Flush();



            context.Response.End();



        }        



    }



 



    public bool IsReusable



    {



        get



        {



            return false;



        }



    }



}


1 comment:

Dani Master said...
This comment has been removed by the author.