Yesterday, I picked up on an old code piece of mine - sending images to the client via an HttpHandler. Why in the world would you implement that with a handler when there is http.sys kernel mode caching? Well, I had a few unique constraints:
- the images had to live outside the Web root and any of its vroots
- the image names had to be concealed because the naming would give away information, and renaming the images prior to publishing on the Web was out of the question
Now, a common approach to sending images from a certain directory (leaving requirement #2 by the wayside for the moment) would be this:
So what is wrong with this approach? First and foremost using an ASP.NET page. The page lifecycle is a drain on performance and throughput, because you simply don't need it. That sorts out why I chose to go with an HTTP handler.
Secondly, somebody could DOS your server. You heard me right. For the background, check the article Trap Alert: Files that aren't. A .NET version (managed C++) of this checker can be found in this download (the article Dateityp-Ermittlung in Managed C++ is only available in German).
How do you get around this issue? Well, how about reading the directory up front, and instead of having the filename in the URL, send the hash! When the image is requested, take the hash and look up the corresponding file, presto. In addition you get one security feature for free: no directory traversals can be hidden in your code.
When I uncovered the code yesterday, I decided to rewrite it for more general use. So what do you get?
- The ImageCacheControls project: it contains the ImageCache class, which does most of the heavy lifting. In addition, you get an ImageCacheControl server control, as well as the implementation of the HTTP handler. (Don't forget to check out the Readme.txt for the latest on feature set and known issues)
- The Web project: a rather simple Web site with demo files in it. The file I want to direct your attention to is Image.ashx. This is the one file - aside from the control project binaries - that needs to be copied to your projects to get started with ImageCache. Note that I made it easy to work with C# (default) or VB.NET.
Usage of ImageCache is demonstrated in default.aspx.cs plus the source code of default.aspx (design time of the control does not work, known issue).
The code behind looks like this (CreateMapping loads the directory contents, initializes the hash to file name map, stores it into the cache):
public partial class _Default : System.Web.UI.Page
protected void Page_Load(object sender, EventArgs e)
// normally, this would be done in global.asax
// the DIY approach to rendering the image tag
string testHash = ImageCache.GetHashForFile("026.jpg", "demo");
Response.Write("<image src=\"Image.ashx?bucket=" +
// the elegant approach to rendering the image tag
Response.Write("<image src=\"" + ImageCache.GenerateUrl("036.jpg", "demo") +
// see HTML source for server control approach (Design time not working, known issue)
Rendering Image tags in Page_Load isn't nice, but after all it is only intended to show the functionality. Most likely you are going to use the declarative ImageCacheControl anyways:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Assembly="ImageCacheControls" Namespace="ChrisOnNET.ImageCache" TagPrefix="cc1" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<form id="form1" runat="server">
<br />Using the ImageCacheControl:
That's basically it. Let me know what you think.
ImageCacheTakeOne.zip (59.55 KB)