I frequently store documents in the database for my ASP.NET apps, eliminating web farm complications with shared drives, permissions, etc. When uploading a file, my Document class reads the uploaded file, zips the file with SharpZipLib, and inserts/updates in the database. When opening a file, I have always used an ASPX page that uses the Document class to unzip the file, and then changes the Content-Disposition and ContentType headers, and then does a BinaryWrite to the Response object to display the file.
I have been using Handlers a lot lately, and figured that it was time to make this process a little more elegant. If you've never written a handler, it's quite simple. You need to make a web.config change, and add a new class that implementts IHttpHandler. All of the work is done in ProcessRequest. Using the default .ashx extension for the handler eliminates the need to make any changes in IIS. I thought about changing the handler to accept all requests with known file extensions with the document ID as the filename, like 3383.pdf. I just figured that using the default extnesion would be easier. Laziness or efficiency, you decide. Check out the code.
In <system.web> in web.config:
<httpHandlers>
<add verb="*" path="DocumentHandler.ashx" type="TestingWebApp.DocumentHandler, TestingWebApp" />
</httpHandlers>
DocumentHandler.cs:
using System;
using System.Web;
namespace TestingWebApp
{
public class DocumentHandler : IHttpHandler
{
private int DocumentId
{
get
{
if(System.Web.HttpContext.Current.Request.QueryString["DocumentId"] != null && System.Web.HttpContext.Current.Request.QueryString["DocumentId"].ToString().Length > 0)
return Convert.ToInt32(System.Web.HttpContext.Current.Request.QueryString["DocumentId"]);
else
throw new ApplicationException("Document Handler requires a DocumentId");
}
}
#region IHttpHandler Members
public void ProcessRequest(System.Web.HttpContext context)
{
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.BufferOutput = false;
Document document = Document.GetDocumentByDocumentId(this.DocumentId);
byte[] buffer = document.UnzippedBinary;
context.Response.ContentType = document.ContentType;
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
}
public bool IsReusable
{
get { return true; }
}
#endregion
}
}