I’m currently preparing a session for a MSDN event in Portugal about Http Handlers, Http Modules and SOAP extensions. I actually never touched the subject until the request for the session came in, so I was really unaware of the possibilities this kind of components offers us. So, when I started to dig in the subject I can honestly say that I was amazed.
“Once upon a time” I had to develop an ISAPI extension to perform some URL redirection and I didn’t like the experience that much. Of course, you always end up being proud of the result if it actually works, but the development experience was far from enjoyable. The .NET components covered in this article allow you to perform most of the functions you would require in ISAPI extensions while giving you the flexibility and the great development experience you already expect when working with .NET.
I have to say that none of the information contained in this article is ground-breaking. I used a lot of resources available on the internet and compiled it into a single, comprehensive article that should shed some light over this all-too-often forgotten subject. Specifically most of my starting knowledge came from the Michelle Bustamante’s TechEd 2004 Session on Extending ASP.NET. Michelle has a very good technical web log where you can find a lot of good examples on using these components www.dasblonde.net.
I divided this article in three parts. In the first I shall cover most of the theory around these components and the ASP.NET pipeline. The second part focus on how you can develop and configure the components, what interfaces should be implemented, what methods you should use, etc.
Finally, on the third part of this article I will give practical examples that will show you how we can use this knowledge to build useful and reusable components that integrate with our web applications.
So, let’s start by understanding how a request gets handled by asp.net in the first place.
When IIS receives a request it will look in the configurations included in its metabase to find out if some sort of special processing should me made. These configurations are actually application mappings that associate resources to ISAPI extensions. All .NET resources (*.aspx, *.asmx, *.resx, etc.) are mapped to an unmanaged ISAPI extension called aspnet_isapi.dll. The function of this dll is to pass requests to asp.net runtime so that they can be handled in our .NET managed code. This is the default configuration but can be extended according to our needs.
This means that only the resources that are mapped to this specific ISAPI extension will be handled by ASP.NET. And this is important because you have to understand the scope of the rules you define in your application configuration files (machine.config and web.config). I’ll give an example on this subject: imagine you have an ASP.NET application in a virtual directory in IIS. That application consists of aspx pages, some images (gifs, jpegs) and a web.config file. All pretty standard. In your web.config file you define the following rule:
<authorization>
<deny users="?" />
<authorization>
What will happen if you open a browser and access an aspx page belonging to this application? As you might expect, unless you can provide some sort of credentials that identify you in the application, your request will not be authorized. But what if you change the URL to reference an image file in the same vdir? Your request will always be satisfied no matter if you provided credentials or not. Why? Because IIS is not configured to hand over the processing of these resources to ASP.NET by default, meaning that the configuration files will not affect this request. Actually, the ASP.NET runtime won’t even know that this request ever existed, because IIS will handle it directly.
Thankfully, we can configure IIS in order to change this behaviour. As you probably guessed, we have to map the required extensions to the aspnet_isapi.dll. That way, the requests will cross the boundary to ASP.NET for processing.
When that happens, ASP.NET will get an HttpApplication object that will be responsible for determining how this request will get processed. This decision will be based on the configuration that you define in machine.config or web.config. Actually what the HttpApplication object does is choosing an HttpHandler or an HttpHandlerFactory object that will in fact process the request and generate the corresponding response.
It may or may not come as a surprise to you, but actually all requests are eventually processed by an Http Handler. Confused? What about the pages that you developed? Well, these are handlers also. As you may know, every aspx page has an object that represents the functionality included in its code behind. This object will always inherit from the Page class that in turn implements an interface called IHttpHandler. So even you’re first Hello World page is actually an Http handler. So you see, this cannot be too complicated.
If you look at machine.config you’ll see the following section:
<httpHandlers>
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>
<add verb="*" path="trace.axd" type="System.Web.Handlers.TraceHandler"/>
<add verb="*" path="*.config" type="System.Web.HttpForbiddenHandler"/>
</httpHandlers>
There are a lot more handlers defined but these will be enough to explain things for now. What this means is that after the mapping at IIS level where it’s decided if a request should be handed over to ASP.NET, there is a second level of mapping, internal to ASP.NET where you assign resources to the components that process them.
In the first mapping you see that all aspx extensions are processed by the PageHandlerFactory. Why a factory? You use a factory when you have several HttpHandler objects available to process the same type of request and you have to make a decision on which one will be used. The page access example is probably the best one I can give you: so, every page has its own code behind object that we now know implements a handler. The job of the PageHandlerFactory is actually to create an instance of that object and pass it to the ASP.NET runtime so that the request can be processed.
In the second example you see that requests targeting trace.axd will be processed by TraceHandler. If you used tracing you know what these requests are. Trace.axd shows you the all the tracing information of your application and it’s used mostly on troubleshooting asp.net applications when in production. Instead of configuring the trace at page-level (which would show you the information on the bottom of the page), you can define it at the application level and view it in trace.axd. Have you ever wondered how this works since the trace.axd file is nowhere to be found on your application? The answer is above: all requests for a trace.axd file will be handled by a component called TraceHandler that dynamically gathers all the info and outputs it in the response stream. So, as you can see the resource doesn’t have to exist if the component that processes the requests that target it doesn’t actually need its contents.
In the third mapping that I presented, all config files are mapped to the HttpForbiddenHandler. The job of this handler is simply to throw an exception. That is the mechanism that prohibits your web.config file to be served by IIS. If this wasn’t configured then IIS would simply serve the file when requested. So remember, IIS is configured to pass requests for *.config resources to ASP.NET. And ASP.NET in turn is configured to use this handler that generates an exception when it receives this kind of requests.
So what does the extension of a resource mean? Actually nothing after the application gets built and deployed. It is just a routing mechanism. Let’s try a simple example. Create a new ASP.NET Web Application in Visual Studio and call it HandlerTest. Add a WebForm called TestExtension.aspx. Add the following code on the code-behind file:
private void Page_Load(object sender, System.EventArgs e)
{
Response.Write(“My really stupid extension test”);
}
Build your application and then rename TestExtension.aspx to TestExtension.rse (where ‘rse’ means Really Stupid Extension J). Try to access TestExtension.rse in Internet Explorer. Nothing shows up right? IIS served the request by sending the contents of the file and the Page_Load method didn’t run. Now add a mapping in IIS for .rse extensions to the aspnet_isapi.dll. Finally add the following information to your web.config file:
<add verb="*" path="*.rse" type="System.Web.UI.PageHandlerFactory" />
Now refresh the page. It worked! Why? Because we mapped the rse extensions to the same handler factory used by aspx applications, so our code-behind object will be created and the method will be executed. This will work for any aspx page no matter how complicated it is.
Now that we understand how the routing of a request is made until it reaches the component that processes it, let’s look at the components that we can use to extend this behaviour.
Http Modules: these are components that are able to interact with the HTTP request throughout the entire round-trip. Meaning, they are not suited to generate a response per-se but are actually there so that you can perform some additional processing over the request and usually build-up some information and include it in the HttpContext object so that it is available for your page or web service to access. Modules can be used for many things and we’ll see in part two that in fact there are already a bunch of modules configured by default that implement things like Session State Management, Windows Authentication, Output Cache management and so on.
Http Handlers: this is a special type of component that is responsible for actually processing a request and generating a response. We know that handlers are created when we develop a page or a web service. So, why would we want to create new custom handlers? To create custom endpoints in our application. In part three you’ll see how we can create a handler for jpeg files that generates thumbnails when we request the image with a specific parameter in the query string or simply sends the flat image if no parameter is specified. You can also create handlers for xml files so you can turn them into reports instead of just sending the xml contents as a response to the browser.
Http Handler Factories: a component that chooses one handler based on request specifics. Used when you have several handlers available to process the same type of request.
SOAP Extensions: a component that only applies to web services invocation and that allows you to interact with the request in the serialization/deserialization stages. Soap extensions are commonly used to encrypt/decrypt the request and the response to provide secure communication, to log invalid messages in their original format or even to enforce authentication by checking information that is sent out of band in a Soap Header (like user credentials).
The following image sums up what we've talked about so far and shows how these components relate in a round-trip. The image presents the pipeline used for processing aspx and asmx resources:

This covers the subject that makes up part one of this article. I hope to be able to post the remaining parts in the next few days. Yes, I know it’s long but things will start to get more interesting once we get to the actual code.