Use Custom Handlers to gather Visitor Information
By Peter A. Bromberg, Ph.D.
Printer - Friendly Version
Peter Bromberg

Some time ago, my site partner Robbe Morris did an in-depth investigation of HttpHandlers with respect to performance considerations. One of the things he did with a handler was to remap a custom image property to a handler that writes an image to the Response stream in an attempt to bypass the baggage of the Page class and see what performance gains could be obtained.

There's another useful way to use an image - generating handler, and that's to gather visitor statistics on a particular page, or even for your whole site, if you want. It's very efficient, and while it doesn't have all the features of say, WebTrends, it sure doesn't take up as many resources either.

The key trick, and it's one that is commonly used in classic ASP and CGI scripts, is to point the src attribute of an IMG tag not directly at an image, but at a page (or in this case, an ASHX handler) that does additional processing and then finally does return an image to make the IMG tag happy.

So for example, with our new concept, your image tag on a page that you want to capture visitor statistics on might look like this:

<img id="stats" .src="ImageHandler.ashx?name=whatever.gif" />

Now let's see exactly what my sample implementation of the hander does with this when it's loaded:

<%@webhandler class='ImageWriter' language='c#'%>
using System; 
using System.Web; 
using System.Drawing; 
using System.Drawing.Imaging;
using System.Text;
using System.IO;

  public class ImageWriter : IHttpHandler 
    public void ProcessRequest(HttpContext ctx) 
        StringBuilder sbLog = new StringBuilder();
        HttpBrowserCapabilities bc = ctx.Request.Browser;
    sbLog.Append(bc.Type + "," + bc.Browser + "," + bc.Version + "," +bc.Platform + "," );
    sbLog.Append(ctx.Request.UrlReferrer +"," +ctx.Request.UserHostAddress + "," 
    + ctx.Request.IsAuthenticated + "," + ctx.Request.HttpMethod + "\r\n");
    FileInfo fi = new FileInfo(ctx.Server.MapPath("log.txt"));
    // use FileMode.Append to not overwrite older entries
    FileStream sWriterAppend  = fi.Open(FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
    sWriterAppend.Write(System.Text.Encoding.ASCII.GetBytes(sbLog.ToString()), 0, sbLog.Length);
    sbLog = null;
    fi = null;
    sWriterAppend = null;
       string sFileName=String.Empty; 
       string sPath=ctx.Server.MapPath("."); 
         sFileName = ctx.Request["name"].ToString().Trim(); 
         if (sFileName.Length <5) { return; }  // must be at least "1.gif" (5 chars)
     ctx.Response.WriteFile(sPath+ @"\images\" + sFileName);
       catch (Exception e) { 
        public bool IsReusable { get { return true; } } 

OK, here's what happens: When the handler loads, it passes control to the ProcessRequest method, along with a reference to the current HttpContext. So the first thing I'm doing here is using the context to get the Request.Browser object, and appending some of the interesting tidbits to my StringBuilder which is basically designed just to create a CSV delimited text file. In production, you would write the information to one or more database tables. After I've assembled all the various pieces of info on the visitor that I want, I write them to a log file. Finally, I simply construct the path to the requested image and just Response.WriteFile it out to the browser!

You can use this for affitliate - tracking programs and things like that. If somebody has an image tag on their page that has querystring items such as "affiliateId=1023&customerId=213409", your handlier can be instructed to dutifully capture and record the number of times that image was viewed or how many times it was clicked, by whom, for which affiliate, and when it happened.

And just so you can see it all in action, here's a link to a test page (view the source of it to see it's code) that will let you choose one of two images and see your own statistical information that it has captured as in the code above:

Visitor Information Test Page

Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform.