643383.inddHi, everyone. Dino Esposito’s newest book, Programming Microsoft ASP.NET 4 (ISBN 9780735643383; 992 pages), is now available. Take a look at this earlier post to read the book’s Introduction, which describes the book’s contents and intended audience.

Today we’d like to share a chapter excerpt from the book. Enjoy.

Chapter 4

HTTP Handlers, Modules, and Routing

Advice is what we ask for when we already know the answer but wish we didn’t.
—Erica Jong

HTTP handlers and modules are truly the building blocks of the ASP.NET platform. Any 
requests for a resource managed by ASP.NET are always resolved by an HTTP handler and
pass through a pipeline of HTTP modules. After the handler has processed the request, the
request flows back through the pipeline of HTTP modules and is finally transformed into
markup for the caller.

The Page class—the base class for all ASP.NET runtime pages—is ultimately an HTTP handler
that implements internally the   page life cycle that fi  res the well-known set of page events, 
including postbacks, Init, Load, PreRender, and the like. An HTTP handler is designed to pro-
cess one or more URL extensions. Handlers can be given an application or machine scope,
which means they can process the assigned extensions within the context of the current
application or all applications installed on the machine. Of course, this is accomplished by
making changes to either the site’s web.config file or a local web.config file, depending on the 
scope you desire.

HTTP modules are classes that handle runtime events. There are two types of public events
that a module can deal with. They are the events raised by HttpApplication (including asyn-
chronous events) and events raised by other HTTP modules. For example, SessionStateModule
is one of the built-in modules provided by ASP.NET to supply session-state services to an 
application. It fi  res the End and Start events that other modules can handle through the 
familiar Session_End and Session_Start signatures.

In Internet Information Services (IIS) 7 integrated mode, modules and handlers are resolved
at the IIS level; they operate, instead, inside the ASP.NET worker process in different runtime
configurations, such as IIS 7 classic mode or IIS 6.

HTTP modules and handlers are related to the theme of   request routing. Originally 
developed for ASP.NET MVC, the   URL routing engine has been incorporated into the over-
all ASP.NET platform with the .NET Framework 3.5 Service Pack 1. The URL routing engine
is a system-provided   HTTP module that hooks up any incoming requests and attempts to
match the requested URL to one of the user-defined rewriting rules (known as routes). If a
match  exists, the module locates the HTTP handler that is due to serve the route and goes
with it. If no match is found, the request is processed as usual in Web Forms, as if no URL
routing engine was ever in the middle. What makes the URL routing engine so beneficial to
applications? It actually enables you to use free-hand and easy-to-remember URLs that are
not necessarily bound to physical fi  les in the Web server.

In this chapter, we’ll explore the syntax and semantics of HTTP handlers, HTTP modules, and
the URL routing engine.

The ISAPI Extensibility Model of IIS

A Web server generally provides an application programming interface (API) for 
enhancing and customizing the server’s capabilities. Historically speaking, the first of
these extension APIs was the Common Gateway Interface (CGI). A CGI module is a new
application that is spawned from the Web server to service a request. Nowadays, CGI
applications are almost never used because they require a new process for each HTTP
request, and this approach poses severe scalability issues and is rather inadequate for
high-volume Web sites.

More recent versions of Web servers supply an alternate and more efficient model to
extend the capabilities of the server. In IIS, this alternative model takes the form of the
ISAPI interface. When the ISAPI model is used, instead of starting a new process for
each request, the Web server loads a made-to-measure component—namely, a Win32
dynamic-link library (DLL)—into its own process. Next, it calls a well-known entry
point on the DLL to serve the request. The ISAPI component stays loaded until IIS is
shut down and can service requests without any further impact on Web server activ-
ity. The downside to such a model is that because components are loaded within the
Web server process, a single faulty component can tear down the whole server and all
installed applications. Some effective countermeasures have been taken over the years
to smooth out this problem. Today, IIS installed applications are assigned to application
pools and each application pool is served by a distinct instance of a worker process.

From an extensibility standpoint, however, the ISAPI model is less than optimal because
it requires developers to create Win32 unmanaged DLLs to endow the Web server with
the capability of serving specific requests, such as those for ASPX resources. Until IIS 7
(and still in IIS 7 when the classic mode is configured), requests are processed by IIS and
then mapped to some ISAPI (unmanaged) component. This is exactly what happens
with plain ASPX requests, and the ASP.NET ISAPI component is aspnet_isapi.dll. In IIS 7.x
integrated mode, you can add managed components (HTTP handlers and HTTP mod-
ules) directly at the IIS level. More precisely, the IIS 7 integrated mode merges the
ASP.NET internal runtime pipeline with the IIS pipeline and enables you to write Web
server extensions using managed code. This is the way to go.

Today, if you learn how to write HTTP handlers and HTTP modules, you can use such
skills to customize how any requests that hit IIS are served, and not just requests that
would be mapped to ASP.NET. You’ll see a few examples in the rest of the chapter.

Writing HTTP Handlers

As the name suggests, an   HTTP handler is a component that handles and processes a 
request. ASP.NET comes with a set of built-in handlers to accommodate a number of system
tasks. The model, however, is highly extensible. You can write a custom HTTP handler when-
ever you need ASP.NET to process certain types of requests in a nonstandard way. The list of
useful things you can do with HTTP handlers is limited only by your imagination.

Through a well-written handler, you can have your users invoke any sort of functionality via
the Web. For example, you could implement click counters and any sort of image manipula-
tion, including dynamic generation of images, server-side caching, or obstructing undesired
linking to your images. More in general, an HTTP handler is a way for the user to send a 
command to the Web application instead of just requesting a particular page.

In software terms, an HTTP handler is a relatively simple class that implements the 
IHttpHandler interface. An HTTP handler can either work synchronously or operate in an
asynchronous way. When working synchronously, a handler doesn’t return until it’s done
with the HTTP request. An asynchronous handler, on the other hand, launches a potentially
lengthy process and returns immediately after. A typical implementation of asynchronous
handlers is asynchronous pages. An asynchronous HTTP handler is a class that implements a
different interface—the IHttpAsyncHandler interface.

HTTP handlers need be registered with the application. You do that in the application’s web.
config
file in the <httpHandlers> section of <system.web>, in the <handlers> section of 
<system.webServer> as explained in Chapter 3, “ASP.NET Configuration,” or in both places. If
your application runs under IIS 7.x in integrated mode, you can also configure HTTP handlers
via the Handler Mappings panel of the IIS Manager.

The IHttpHandler Interface

Want to take the splash and dive into HTTP handler programming? Well, your first step is
getting the hang of the IHttpHandler interface. An HTTP handler is just a managed class
that implements that interface. As mentioned, a synchronous HTTP handler implements the
IHttpHandler interface; an asynchronous HTTP handler, on the other hand, implements the
IHttpAsyncHandler interface. Let’s tackle synchronous handlers first.

The contract of the IHttpHandler interface defines the actions that a handler needs to take to
process an HTTP request synchronously.

Members of the IHttpHandler Interface

The IHttpHandler interface defines only two members: ProcessRequest and IsReusable, as
shown in Table 4-1. ProcessRequest is a method, whereas IsReusable is a Boolean property.

image

The IsReusable property on the System.Web.UI.Page class—the most common HTTP handler
in ASP.NET—returns false, meaning that a new instance of the HTTP request is needed to
serve each new page request. You typically make IsReusable return false in all situations
where some significant processing is required that depends on the request payload. Handlers
used as simple barriers to filter special requests can set IsReusable to true to save some CPU
cycles. I’ll return to this subject with a concrete example in a moment.

The ProcessRequest method has the following signature:

void ProcessRequest(HttpContext context);

It takes the context of the request as the input and ensures that the request is serviced. In
the case of synchronous handlers, when ProcessRequest returns, the output is ready for 
forwarding to the client.

A Very Simple HTTP Handler

The output for the request is built within the ProcessRequest method, as shown in the 
following code:

using System.Web;
namespace AspNetGallery.Extensions.Handlers
{
    public class SimpleHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            const String htmlTemplate = "<html><head><title>{0}</title></head><body>" +
                                        "<h1>Hello I'm: " +
                                        "<span style='color:blue'>{1}</span></h1>' +
                                        "</body></html>";
            var response = String.Format(htmlTemplate,
                     "HTTP Handlers", context.Request.Path);
            context.Response.Write(response);
        }
        public Boolean IsReusable
        {
            get { return false; }
        }
    }
}

You need an entry point to be able to call the handler. In this context, an entry point into the
handler’s code is nothing more than an HTTP endpoint—that is, a public URL. The URL must
be a unique name that IIS and the ASP.NET runtime can map to this code. When registered,
the mapping between an HTTP handler and a Web server resource is established through the
web.config file:

<configuration>
    <system.web>
        <httpHandlers>
            <add verb="*"
                 path="hello.axd"
                 type="Samples.Components.SimpleHandler" />
        </httpHandlers>
    </system.web>
    <system.webServer>
        <validation validateIntegratedModeConfiguration="false" />
        <handlers>
            <add name="Hello"
                 preCondition="integratedMode"
                 verb="*"
                 path="hello.axd"
                 type="Samples.Components.SimpleHandler" />
        </handlers>
    </system.webServer>
</configuration>

The <httpHandlers> section lists the handlers available for the current application. These 
settings indicate that SimpleHandler is in charge of handling any incoming requests for an
endpoint named hello.axd. Note that the URL hello.axd doesn’t have to be a physical resource
on the server; it’s simply a public resource identifier. The type attribute references the class
and assembly that contain the handler. Its canonical format is type[,assembly]. You omit the
assembly information if the component is defined in the App_Code or other reserved folders.

Important   As noted in Chapter 3, you usually don’t need both forms of an HTTP handler 
declaration in <system.web> and <system.webServer>. You need the former only if your applica-
tion runs under IIS 6 (Windows Server 2003) or if it runs under IIS 7.x but is configured in classic
mode. You need the latter only if your application runs under IIS 7.x in integrated mode. If you
have both sections, you enable yourself to use a single web.config file for two distinct deploy-
ment scenarios. In this case, the <validation> element is key because it prevents IIS 7.x from
strictly parsing the content of the configuration file. Furthermore, as discussed in Chapter 3, the
<httpHandlers> and <httpModules> sections help in testing handlers and modules within Visual
Studio if you’re using the embedded ASP.NET Development Server (also known as, Cassini).

If you invoke the hello.axd URL, you obtain the results shown in Figure 4-1.

image

The technique discussed here is the quickest and simplest way of putting an HTTP handler to
work, but there is more to know about the registration of HTTP handlers and there are many
more options to take advantage of.

Note  It’s more common to use the ASHX extension for a handler mapping. The AXD extension
is generally reserved for resource handlers that inject embedded content such as images, scripts,
and so forth.

[end of excerpt]

Here is the chapter’s complete head structure, to give you a sense of its full coverage:

Writing HTTP Handlers

The IHttpHandler Interface

Members of the IHttpHandler Interface

A Very Simple HTTP Handler

Registering the Handler

Preconditions for Managed Handlers

Handlers Serving New Types of Resources

The Picture Viewer Handler

Designing the HTTP Handler

Implementing the HTTP Handler

Serving Images More Effectively

Loading Images from Databases

Serving Dynamically Generated Images

Writing Copyright Notes on Images

Controlling Images via an HTTP Handler

Advanced HTTP Handler Programming

Deploying Handlers as ASHX Resources

Prevent Access to Forbidden Resources

Should It Be Reusable or Not?

HTTP Handler Factories

Asynchronous Handlers

Implementing Asynchronous Handlers

Writing HTTP Modules

The IHttpModule Interface

A Custom HTTP Module

Wiring Up Events

Registering with the Configuration File

Accessing Other HTTP Modules

Examining a Real-World HTTP Module

The UrlRoutingModule Class

The PostResolveRequestCache Event

URL Routing

The URL Routing Engine

Original URL Rewriting API

URL Patterns and Routes

Routing in Web Forms

Defining Routes for Specific Pages

Programmatic Access to Route Values

Structure of Routes

Preventing Routing for Defined URLs

Summary