Login


Writing a Custom HTTP Handler in ASP.NET

By Jonathan Wood on 1/12/2011 (Updated on 1/22/2011)
Language: C#
Technology: ASP.NET
Platform: Windows
License: CPOL
Views: 68,847
Web Development » ASP.NET » General » Writing a Custom HTTP Handler in ASP.NET

Screenshot of Demo Website

Download Source Code Download Source Code

Introduction

In recent years, there appears to be a merging between ASP.NET and Internet Information Services (IIS), Microsoft's Windows-based web server application. The result is that more and more server settings can be specified in your web application's web.config file.

I don't know about you but, not really being an "admin" guy, I'm really excited about this. It means I can make more customizations in my web.config file without having to delve into IIS. This is particularly cool if your site runs on a shared hosting account, where some IIS settings may not be available on a per-application basis. In addition, it also means that those settings can easily be transferred to another server should you need to move your site in the future.

If you are using ASP.NET 4.0 and IIS7 or later, implementing a custom HTTP handler is now much easier than it may have been in the past.

An HTTP handler is the routine that services a request for a particular group of files, or file types. For example, requests for ASPX files are handled through ASP.NET's Page HTTP handler, while graphics files such as JPG are not. If you wanted to implement special handling of request for JPG files, you can't do so from an ASPX file because ASP.NET code, by default, does not run when a request for these files are received.

However, you can create a handler for these files from ASP.NET if you create a custom HTTP handler. For example, what if you wanted to prevent other sites from linking to your graphics files? You could implement your own HTTP Handler that would see if the request came from tha same domain and, if not, deny the request. And thanks to improved integration between ASP and IIS, you can do it without tweaking IIS.

Creating a Custom HTTP Handler

Listing 1 shows my custom JpgHttpHandler. The class implements IHttpHandler and, as a result, must implement ProcessRequest() and IsReusable.

This is a very simple handler that starts by seeing if the request came from the current domain. If not, HTML markup for an "Access Denied" message is constructed and returned. Otherwise, the request file is written to the response stream. If an error occurs while writing the file, the code assumes the file does not exist and constructs and returns markup indicating that, while access was granted, the requested file was not found.

Listing 1: Custom HTTP Handler

using System;
using System.Globalization;
using System.Web;

public class JpgHttpHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;

        // Try and prevent request from a different domain
        if (request.Url != null && request.UrlReferrer != null)
        {
            if (String.Compare(request.Url.Host, request.UrlReferrer.Host,
                true, CultureInfo.InvariantCulture) != 0)
            {
                response.Write("<html>\r\n");
                response.Write("<head><title>JPG HTTP Handler</title></head>\r\n");
                response.Write("<body>\r\n");
                response.Write("<h1>Access Denied</h1>\r\n");
                response.Write("</body>\r\n");
                response.Write("</html>");
                return;
            }
        }

        // Otherwise transfer requested file
        try
        {
            response.ContentType = "application/jpg";
            response.WriteFile(request.PhysicalPath);
        }
        catch
        {
            response.Write("<html>\r\n");
            response.Write("<head><title>JPG HTTP Handler</title></head>\r\n");
            response.Write("<body>\r\n");
            response.Write("<h1>Access Granted but file was not found</h1>\r\n");
            response.Write("</body>\r\n");
            response.Write("</html>");
        }
    }

    public bool IsReusable
    {
        get { return true; }
    }
}

I should point out that, while this code is potentially very useful and is a great example of how an HTTP handler might be used, the technique shown is not foolproof. If you had to be absolutely certain that some content could not be accessed by some people, more sophisticated techniques would be needed.

Mapping the Handler

Now that we've written the HTTP handler, let's map it to JPG files so that this handler will be used for all requests for files with the JPG extension.

I actually ran into considerable trouble while first working this out. Initially, I added an <httpHandlers> section under <system.web>. The trouble was that this worked just fine. Or, at least, it worked just fine on my development machine. Once I got everything how I wanted and uploaded it to my server, the site failed with a server error 500.

For this to work correctly on the server, an entry is needed under <system.webServer>. Interestingly, once I made this change, it did NOT work on my development machine. The server that comes with Visual Studio for debugging obviously does not behave exactly like IIS7. This can occasionally be a source of frustration and lost time. At any rate, the main concern here is getting it to work on the server and so I had to go with the <system.webServer> section!

Listing 2 shows my entire web.config file. The <system.webServer> element was introducted with ASP.NET 4.0 and IIS7. Whereas this would have previously required making changes directly to IIS, this is all that's needed to implement our custom HTTP handler for JPG files.

Listing 2: Web.config File

<?xml version="1.0"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0"/>
    </system.web>
    <system.webServer>
        <handlers>
            <add verb="*" path="*.jpg" name="JpgHttpHandler" type="JpgHttpHandler"/>
        </handlers>
    </system.webServer>
</configuration>

Conclusion

And that's really all there is to it. The attached website project has a default page with a link to a graphics file. Since the request will be from the same domain, the graphics file will be displayed. You can modify the handler's logic to have the "Access Denied" message displayed. Or you can enter the name of a non-existent JPG file to invoke the "file not found" message.

All customizations should be this easy! Hopefully, Microsoft will continue this integration of ASP.NET and IIS.

End-User License

Use of this article and any related source code or other files is governed by the terms and conditions of The Code Project Open License.

Author Information

Jonathan Wood

I'm a software/website developer working out of the greater Salt Lake City area in Utah. I've developed many websites including Black Belt Coder, Insider Articles, and others.