Custom HTTP Handlers

Harness the Power for Yourself

CoreCoder

LANGUAGES: C#

ASP.NET VERSIONS: 1.0 | 1.1

 

Custom HTTP Handlers

Harness the Power for Yourself

 

By Dino Esposito

 

As a brilliant ASP.NET developer, and a loyal reader of asp.netPRO magazine, you know that any page request (or Web service request) is picked up and serviced by a specialized HTTP handler component. Whenever a request comes in, IIS looks up its metabase to find a match between the verb and file extension of the requested URL and any components registered to handle incoming requests.

 

For example, when an .aspx request comes in, IIS knows from the metabase that the request should be routed to a component named aspnet_isapi.dll. The aspnet_isapi.dll module is an old-style, Win32 DLL that provides the common skeleton of ISAPI modules. (ISAPI modules are Win32 DLLs that add custom functionality to IIS.)

 

All requests routed to the ASP.NET ISAPI module undergo a second filter: ASP.NET HTTP handlers. The ASP.NET runtime checks the verb and path of the URL, and dispatches the request to a selected HTTP handler. For each application, the list of supported HTTP handlers is hard-coded in the configuration files. The list of standard HTTP handlers can be found in the section of the machine.config file. In the web.config file, instead, you define handlers specific to the current application. By default, ASPX requests are handled by the Page class; ASMX requests for Web services are routed to the WebServiceHandler-based class.

 

Overall, an HTTP handler is the managed component that takes care of serving ASP.NET requests that match a given range of criteria, such as URL formatting, extension, path, and query string. In this article, I'll briefly discuss the basics of HTTP handlers and illustrate a sample handler that I find extremely useful to develop and test Web applications.

 

Learn to Use Handlers

Speaking of HTTP handlers, one common question goes like this: Will handlers be helpful to implement feature X? Where "feature X" is, for whatever reasons, difficult for developers to implement quickly and efficiently. Golden rules for understanding the real goal and scope of HTTP handlers can be summarized as follows:

  • HTTP handlers are managed classes used to service certain Web requests.
  • HTTP handlers represent an optionally virtual URL.
  • The base ASP.NET Page class is an HTTP handler.
  • The HTTP handler merely and uniquely processes an incoming request.
  • HTTP handlers have neither access nor influence on application-level events, such as BeginRequest, AcquireSessionState, or PreSendRequestContent.

 

If your application is only concerned with ASPX pages, you don't need to care much about HTTP handlers. Handlers are quite helpful to reference any server resources through a URL. For example, you can use an HTTP handler to generate dynamic images and bind them to the tag. The tag is the only HTML element that can display images on the Web, and it only accepts images via a URL. By using a custom HTTP handler, you can return an image created programmatically using GDI+, retrieved from a database using ADO.NET, or simply retrieved from the ASP.NET cache.

 

Should you use a handler or just an ad hoc page for this and similar purposes? Note that the ASP.NET Page class is a handler itself, albeit a pretty rich and sophisticated one. As far as image generation is concerned, you don't need the viewstate or postback management that are hard-coded in the Page class. For this reason, using a custom HTTP handler is a preferable approach from a performance standpoint.

 

Just as HTTP handlers are employed to service a given request, they can be used to deny any undesired request. For example, type the URL to your application's web.config file in the browser's address bar. You get an error page. To block user access to a given set of resources, you can tweak your application's web.config file, as follows:

 

  

    type="HttpForbiddenHandler"/>

 

The path attribute indicates which resources will be blocked; more in general, it indicates which resources, and for which verbs, will be subject to the specified HTTP handler component. The HttpForbiddenHandler class is a built-in handler defined in the System.Web namespace. The preceding configuration script is extracted from machine.config, but can be adapted and employed in any application.

 

Another interesting example of system HTTP handlers is trace.axd. Trace.axd is the name of an ASP.NET utility used to track the trace logs of a given page or application (see Figure 1). You call trace.axd by appending the name of the handler to the application's name. Although trace.axd is used as the name of a server-side resource, it's a purely virtual resource; no file or folder exists on the Web server with that name.

 

So what's up? IIS picks up the request for trace.axd and forwards it to ASP.NET, without verifying that a resource with that name really exists. ASP.NET, in turn, routes the request to the HTTP handler of choice. In the end, the handler gets to work on a request that takes the form of a URL resource. Most HTTP handlers, including the handler for ASPX pages, assume that a file lives behind that URL, map the path to the physical file, and do something with it. However, as long as the URL carries enough information for the selected HTTP handler, there's no need to resort to a server-side file. In other words, the URL can be seen as the command that triggers the handler. In this perspective, the command can be anything that the handler can understand - including, but not limited to, a server file name.

 


Figure 1: Trace Viewer lists the requests to a given application with trace log details.

 

Sample Handlers

The list of useful things you can do with HTTP handlers is only limited by your imagination. Through a well written handler, you can have your users invoke any sort of functionality via the Web. An inspiring MSDN article that shows creative uses of HTTP handlers is http://msdn.microsoft.com/library/en-us/dnaspp/html/httphandl.asp. In particular, I'd like to mention the following features that can be effectively coded through handlers:

  • Click counters.
  • Image manipulation (dynamic generation, advanced smart caching, obstructing undesired linking to your images).
  • Reference images and other Web resources from assemblies (useful if you develop rich controls that consume images).
  • Reference JavaScript code in client pages (useful if you don't want to make your client code immediately visible through the browser's View Source menu).

 

By the way, you'll find all these features implemented at various levels and in various ways in ASP.NET 2.0. To demonstrate the power of handlers, I'll show you a couple of HTTP handlers that I use often to inspect code and form a quick idea of how pages that I've never seen before are laid out and function (when I don't have the Visual Studio.NET project available).

 

Outline the Handler

As mentioned, an HTTP handler is a managed class that implements the IHttpHandler interface. The sample handler is named SourceHandler and is outlined as follows:

 

public class SourceHandler : IHttpHandler

{

  public SourceHandler() { ... }

 

  // Override the ProcessRequest method

  public void ProcessRequest(HttpContext context) { ... }

 

  // Override the IsReusable property

  public bool IsReusable

  {

    get { return true; }

  }

}

 

The IHttpHandler interface is made of two members: ProcessRequest and IsReusable. The former is a method and takes the HTTP context of the ongoing request, processes the HTTP payload, and generates the response for the caller (typically, but not necessarily, the browser). The response is generated by writing to the output stream using the familiar Response object either directly or through the rendering engine of Web server controls. The IsReusable member is a read-only property indicating whether another request in the same application can use the current instance of the handler. The ProcessRequest method represents the core of each handler.

 


Figure 2: Edit the IIS metabase to register a custom ASP.NET handler to service mydata requests.

 

For ASP.NET handlers to work, two preliminary requirements should be met. First and foremost, you must ensure that IIS routes to ASP.NET all requests you want the handler to process. Second, you must configure ASP.NET to forward those requests to your handler. You decide which extensions the handler will manage. Next, you edit the IIS metabase so that IIS forwards those requests to aspnet_isapi.dll - the ASP.NET entry point in the IIS space (see Figure 2). After you've done this, all requests for, say, a .mydata resource that originate in an application will be routed to the ASP.NET AppDomain of the specified application. To redirect these requests to the handler, edit the web.config as follows:

 

  

    type="AspNetPro.YourHandler, YourHandler" />

 

The .mydata resource doesn't have to be a server file, but its invocation triggers the handler and generates a response. Likewise, you can register the handler with a particular URL. For example, the trace viewer is activated if the target URL of the call is trace.axd.

 

The sample handler, named SourceHandler, is triggered by a call to source.axd and returns the source code of the specified ASPX file. This handler is useful during the development cycle to view the source of a page without accessing the Visual Studio.NET project. The typical call to the handler is shown here:

 

http://localhost/.../source.axd/page.aspx

 

For obvious reasons, the handler works on local requests only. The handler finds the name of the page to process in the query string, or appended to the URL. Figure 3 shows the full source. The ProcessRequest method gets the URL of the request, and ensures the host is local. Then it cuts the source.axd string from the URL and maps the resulting string to a server path. Finally, it opens the .aspx source file using a stream reader, and copies the contents into a read-only text area (see Figure 4).

 

public class SourceHandler : IHttpHandler

{

  public SourceHandler() { }

 

  // Override the ProcessRequest method.

  public void ProcessRequest(HttpContext context)

  {

    // Check if local

    if (!context.Request.Url.IsLoopback)

    {

      context.Response.Write(

        "Unable to process the request.");

       return;

    }

    // By design, the URL has the form: xxx.axd/page.

    string url = context.Request.Url.ToString();

   

    // Check the working mode (source/compiled).

    string output = "";

    if (url.IndexOf("/source.axd/") >0)

      output = RetrieveAspxSource(context.Request.Url);

    else

    {

      context.Response.Write(

        "Unable to process the request.");

      return;

    }

    // Output.

    context.Response.Write("

Source: " + url + "

");

    context.Response.Write("


");

    context.Response.Write(

      "");

  }

 

  // Override the IsReusable property.

  public bool IsReusable

  {

     get { return true; }

  }

 

  // Private members.

  private string RetrieveAspxSource(Uri u)

  {

    // Drop the handler string from the URL.

    string handler = "/source.axd";

    string url = u.ToString().Replace(handler, "");

    UriBuilder builder = new UriBuilder(url);

    // Get the server path to the ASPX file.

    string file = HttpContext.Current.Server.MapPath(

                    builder.Uri.LocalPath);

    // Read the source code.

    StreamReader reader = new StreamReader(file);

    string source = reader.ReadToEnd();

    reader.Close();

 

    return source;

  }

}

Figure 3: The source code of SourceHandler to view the source of the specified ASPX file.

 


Figure 4: The source.axd handler in action.

 

To register the source handler with your application, enter the following script into the web.config file:

 

  

    type="AspNetPro.SourceHandler, SourceHandler"/>

 

The SourceHandler HTTP handler allows you to take a quick look at the structure of a given Web page through the browser and in all those situations in which you don't have Visual Studio.NET available (i.e. a test environment).

 

This idea is nothing really new, and several similar tools are available over the Web; let me try to go one step further. What if the handler returns the source code of the class that ASP.NET creates to service the request? The source code of this file is left on the Web server when the application operates in debug mode. (A feature you can toggle on and off through the web.config file.) Add the following code to the configuration file and bind the handler to the compiled.axd URL:

 

  

    type="AspNetPro.SourceHandler, SourceHandler" />

 

ASP.NET parses the source code of the requested ASPX resource, and stores the resulting class in the directory pointed to by the following property:

 

string tempDir = HttpRuntime.CodegenDir;

 

In this folder, each requested page is accompanied by an XML file that contains the name of the dynamic class and assembly. Using this information, you retrieve the path of the dynamically created class and display its source code (see Figure 5). Note that this source code is just the code that ASP.NET shows whenever you get a compiler error. Using this handler, you can get it whenever the debug mode is on. For more information, download the companion code. A source file for the page must exist for the compiled.axd handler to work. If you don't get it, point the browser to the page first (in ASP.NET debug mode) and then retry with the handler. Finally, note that this code may not work in ASP.NET 2.0.

 


Figure 5: The compiled.axd handler in action.

 

Conclusion

Along with HTTP modules, HTTP handlers are the building blocks of the ASP.NET platform. Everything that occurs under the hood of the ASP.NET runtime environment occurs because of HTTP handlers. When you invoke a Web page, or a Web service method, an appropriate HTTP handler gets into the game and serves your request. ASP.NET includes several predefined handlers, but you can write handlers of your own to perform a variety of tasks and process any sort of user-defined URL.

 

The sample code in this article is available for download.

 

Dino Esposito is a Wintellect trainer and consultant who specializes in ASP.NET and ADO.NET. Author of Programming Microsoft ASP.NET and Introducing ASP.NET 2.0, both from Microsoft Press, Dino also helped several companies architect and build effective products for ASP.NET developers. Dino is the cofounder of http://www.VB2TheMax.com, a popular portal for VB and .NET programmers. Write to him at mailto:[email protected] or join the blog at http://weblogs.asp.net/despos.

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish