Use Custom Http Handlers To Improve Performance in ASP.NET

By Robbe D. Morris

Printer Friendly Version

Robbe Morris
Robbe & Melisa Morris
While reading a chapter from the upcoming book from Addison-Wesley entitled Essential ASP.NET with Examples in C#, I ran across a chapter on creating custom http handlers in .NET.  The author (Fritz Onion) did a great job of explaining how to create, configure, and utilize these custom handlers.  In simplistic terms, you can create a class library assembly then link directly to your assembly without going through a standard .aspx page.
For the remainder of this article, a standard .aspx page is to be considered one that utilizes codebehind with server-side form elements.  In most cases, this is how developers set up their ASP.NET projects.
I was instantly curious about how much overhead could potentially be avoided by bypassing the Page base class that automatically gets invoked in codebehind pages.  Turns out, it pretty consistently performs similar tasks with no server-side controls (normal client side html controls were used instead) about 8-10% faster than the same codebehind page with server controls.  It also performed about 5% faster than an .aspx page with no server-side controls.  Now, I don't consider these percentages to be truly scientific.  They came from running a series of 6 trial runs on each scenario and averaging the results.  A WinXP Pro 1ghz/500MB RAM PC was used and the same test was run on a Win2k Server with dual processors and 1.5GB of RAM.  Similar percentages in Requests Per Second were found on both machines.  The custom http handler averaged 234 RPS, codebehind 210 RPS, and the script only .aspx with no server controls did 226 RPS.  The consistent difference in performance was enough to spark this article and provide custom http handlers as an additional option to enhance overall site performance.


It is important to note that this article is not intended as means to prove one methodology is better than the other.  However, small percentage gains in pages that don't really need codebehind functionality could make a big difference in medium to high traffic sites.  In many of the projects I work on, we send binary data over http either from site to site or desktop to site.  The .aspx pages simply receive the incoming request and process it.  This is an excellent example of how custom http handlers could improve my overall site performance.  I wouldn't necessarily recommend custom http handlers over using codebehind in .aspx pages in normal ASP.NET applications where user interfaces are required.  So, as always, carefully review the requirements of your project and make your own determination as to whether this can help.
Actually creating and configuring your site to use a custom http handler is pretty simple.  Follow these steps to configure your site to use the sample code available here: source code.  The source code will contain one folder called Test that contains a script only page sample along with the CustomHandler assembly and should be set up as it's own site in IIS.  The other folder Test2 is a second site with the codebehind assembly.
Now that you've unzipped the source code and set up two different sites on your computer, it is time to configure IIS in the Test site to accept your chosen file extension mapping.  In the web.config file in the Test site, we'll need to add a node called httpHandlers and populate it.  The verb attribute can be set to GET, PUT, or * if you don't want to place any restrictions on the types of requests it can receive.  The path argument is totally up to you.  I chose get.imgw for reasons I won't get into here.  The path attribute value determines the filename in the URL that will point to your assembly.classname and assembly defined in the type attribute.  Here's an example, http://localhost/get.imgw would automatically invoke CustomHandler.Writer when browsed to even though no physical file of get.imgw exists anywhere.  Of course, you can also use querystring values just like any other link (ex. http://localhost/get.imgw?id=1).

Web.config for Test site
   <?xml version="1.0" encoding="utf-8" ?>
 <configuration>
   <system.web>
      <httpHandlers>
           <add verb="GET" path="get.imgw" type="CustomHandler.Writer, CustomHandler" />
      </httpHandlers>
      </system.web>
 </configuration>
Open the IIS site manager back up and select Properties for the Test site.  Click the Home Directory tab and then click Configuration tab.  On the Mappings tab, click Add to add your .imgw file extension to the list of handlers and assign it to the aspnet_isapi.dll.  Click Ok and close the IIS site manager.
Here is the source code for the CustomHandler namespace's Writer class.  The current HttpContext is made available in the class via the ProcessRequest method that gets triggered when a request is made.  Also notice that we've implemented the IHttpHandler interface.  Unlike using a custom handler through .ashx pages, you have the option to pool instances of your handler via setting the IsReusable property to a value of true.  In .ashx pages, setting this to true is overriden to false.  My testing reflected an almost identical level of performance whether this property was set to true or false.  MSDN does mention a slight performance improvement with a setting of true.  I've included a sample .ashx page source code for you to review as well.  One great thing about .ashx pages is that they do not require extension registration in IIS or any entries in the web.config file.  The page still goes through the same parsing phase that .aspx pages go through but the IHttpHandler is implemented directly instead of being derived from the Page base class.

CustomHandler.Writer Class Source Code
using System;
using System.Web;


namespace CustomHandler
{

   public class Writer : IHttpHandler
   { 
      public void ProcessRequest(HttpContext oContext)
      {
 
        oContext.Response.Write("<HTML>");
        oContext.Response.Write("<HEAD>");
        oContext.Response.Write("<title>WebForm1</title>");
        oContext.Response.Write("</HEAD>");
        oContext.Response.Write("<body>");
        oContext.Response.Write("<form name='Form1' method='post' action='get.imgw' id='Form1'>");
        oContext.Response.Write("<input name='TextBox1' type='text' value='text textbox value' id='TextBox1' >");
        oContext.Response.Write("</form>");
        oContext.Response.Write("</body>");
        oContext.Response.Write("</HTML>");
 
      }

      public bool IsReusable { get { return true; } }
 }
}
Writer.ashx Source Code
<%@ WebHandler Language="C#" Class="Writer" %>
using System;
using System.Web;


namespace CustomHandler
{

   public class Writer : IHttpHandler
   { 
      public void ProcessRequest(HttpContext oContext)
      {
 
        oContext.Response.Write("<HTML>");
        oContext.Response.Write("<HEAD>");
        oContext.Response.Write("<title>WebForm1</title>");
        oContext.Response.Write("</HEAD>");
        oContext.Response.Write("<body>");
        oContext.Response.Write("<form name='Form1' method='post' action='get.imgw' id='Form1'>");
        oContext.Response.Write("<input name='TextBox1' type='text' value='text textbox value' id='TextBox1' >");
        oContext.Response.Write("</form>");
        oContext.Response.Write("</body>");
        oContext.Response.Write("</HTML>");
 
      }

      public bool IsReusable { get { return true; } }
 }
}
To run the samples for the Test site, click http://localhost/script_only.aspx to look at a standard .aspx page.  http://localhost/writer.ashx to see a custom handler via an .ashx page.  http://localhost/get.imgw to load the custom handler inside the CustomHandler assembly.
Running the sample for the Test2 site, just browse to http://localhost/webform1.aspx.
There you have it.  It's that simple.  You've been armed with one more alternative to optimize your web site.
By the way, custom http handlers can also be used to write multiple images to a page without allowing the images to be cached in the temporary internet files folder.  While the user can still convert the html from the page into your image, you could use the handler to prevent remote sites from linking to your images at runtime.  If you need the source code for that, click here and modify the code to ensure the request came from your site.


Robbe has been a Microsoft MVP in C# since 2004.  He is also the co-founder of NullSkull.com which provides .NET articles, book reviews, software reviews, and software download and purchase advice.