Web App Design: Avoid Writing to Disk, Part 2

Dasher left an interesting comment to my previous post on avoiding writing to disk:

Don't you hit the reverse problem with needing to save the image to a file for displaying in a webpage?

Nope, you can do the reverse just as easily.  The trick is figuring out how to get the stream from the database and applying it to the ASP.NET Image control. 

A simple solution is to create an HttpHandler that will serve as a dynamic image generator.  To do this, create a Generic Handler (.ashx) and add the following code:

 <%@ WebHandler Language="C#" Class="ImageHandler" %>

using System;
using System.Web;
using System.Drawing.Imaging;
using System.Data.SqlClient;
using System.IO;

public class ImageHandler : IHttpHandler 
{
    private HttpResponse _response;
    
    private HttpResponse Response
    {
        get { return _response; }
    }
    
    public void ProcessRequest (HttpContext context) 
    {
        _response = HttpContext.Current.Response;
        
        Response.ContentType = "image/pjpeg";
        SqlConnection cn = new SqlConnection(
        @"Database=AdventureWorks;Server=(local);
     Integrated Security=true;");
        cn.Open();
        SqlCommand select = new SqlCommand(@"
    SELECT      LargePhoto
    FROM         Production.ProductPhoto
    WHERE     (ProductPhotoID = 182)", cn);

        try
        {
            byte[] imageBytes = (byte[])select.ExecuteScalar();
            MemoryStream mem = new MemoryStream(imageBytes);
            System.Drawing.Image image = System.Drawing.Image.FromStream(mem);
            image.Save(Response.OutputStream, ImageFormat.Jpeg);
        }
        catch (SqlException oops)
        {
            Response.ContentType = "text/html";
            Response.Write(oops.ToString());
        }
        finally
        {
            select.Dispose();
            cn.Close();
            cn.Dispose();
        }
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }
}

I saved my generic handler as "ImageHandler.ashx".  To use the image handler, simply reference it as the ImageUrl from the image control that you want to use:

<asp:Image ID="Image1" ImageUrl="~/ImageHandler.ashx" runat="server" />

Admittedly, this is a pretty simple implementation.  I leave it as an exercise for the reader to leverage the ASP.NET Cache to cache requests for the image based on ID and return the image from the cache rather than hit the database.  You might also implement security for the requested image, checking to see if the current user has access to the image data or not.

Funny, but I just realized I had a case of deja vu, since I had gone through this same conversation regarding base64 encoding an image and base64 decoding an image.