Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Tracking downloads using an HTTPHandler

0.00/5 (No votes)
15 Jan 2011 1  
Using an HTTPHandler to make calls to the business layer to update file download count.
Not long ago, I developed a freeware application and made it available on my site for download. In a short period of time, it has started to become somewhat popular, can tell by download stats on some of the other sites where I made it available so I wanted to be able to track the number of downloads of any of the files that were being downloaded from my site and this is the solution I came up with.

In the pipeline, the Handler is called last and when it is called, the appropriate HTTPHandler is executed. Since the HTTPApplication object will call the HTTPHandler to process the request and generate a response, we can use our handler to implement our call to the business layer to update the count for the file in question and fulfill the request for the download.

To accomplish this, I use a modified anchor tag instead of the usual anchor tag that makes a call to our handler like so:
//Old way
<a href="path_to_file.ext" />Some Text

//New way
<a href="DownloadHandler.ashx?file=path_to_file.ext" />Some Text

The code below is a copy of the handler code that I use on my site. I have read in many places that the handler needs to be registered in the Web.config file, but when I tried this it did not work, so I didn't register it and just call it as described above. The magic that makes this work is the few lines starting at the Content-Disposition which is the file name that is suggested in the File|Save As Dialog. Content-Length is the maximum size of the data to be transferred, caution do not set this value to low as it will end prematurely and the downloaded file will most likely be corrupt. Next, we tell it what we want to download and in this case the application/octet-stream specifies that it is a binary file and finally output the file using the context.Response.WriteFile.
C#
<%@ webhandler language="C#" class="DownloadHandler"; %>
using System;
using System.Web;
using System.Web.UI.HtmlControls;
using System.IO;
    public void ProcessRequest(HttpContext context)
    {
        //Retrieve file name from URL and append my downloads path
        string fileName = context.Request.QueryString["file"].ToString();
        string filePath = HttpContext.Current.Server.MapPath("~/downloads/" + fileName);
        //Be sure the file exists
        FileInfo file = new System.IO.FileInfo(filePath);
        if (!file.Exists)
        {
            context.Response.StatusCode = 500;
            context.Response.End();
            return;
        }
        //Call to business layer to update the count based on the filename
        DownloadsService.UpdateDownloadCount(fileName);
        //Don't allow response to be cached
        context.Response.Clear();
        context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        context.Response.Cache.SetNoStore();
        context.Response.Cache.SetExpires(DateTime.MinValue);
        //The next few lines is what actually starts downloads the file.
        context.Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
        context.Response.AddHeader("Content-Length", file.Length.ToString());
        context.Response.ContentType = "application/octet-stream";
        context.Response.WriteFile(file.FullName);
        context.ApplicationInstance.CompleteRequest();
        context.Response.End();
    }
    public bool ValidateParameters(HttpContext context)
    {
        return true;
    }
    public bool IsReusable
    {
        get
        {
            return true;
        }
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here