One of the things I love most about training is the constant real world questions and scenarios that students bring to the table. Yesterday I received an email from a former student asking about how they could log a little bit of information passed in the query string of a URL (for example, a CustomerID). As it turns out, that’s a relatively easy feature to implement – simply use an HTTP module.
An HTTP module gives you the ability to slide custom code into the handling of pages, allowing you to customize behavior or add additional functionality. Our HTTP module will fire for any file being requested if IIS 7 or later is in use, or just ASP.NET files (ASPX, ASMX, etc.) if IIS 6 is in use. In this case, the HTTP module is the perfect choice, because it will execute for every page, so anywhere we have the CustomerID in the query string we can grab it.
You might be thinking at this point – wait a minute… I can do that in my global.asax file.
And you’re right, many times you can. However, an HTTP module does have a few advantages. First, an HTTP module is more, well, modular. It’s much easier for me to add and remove it from different web applications; I can register the DLL that contains the HTTP module in the GAC and access it from multiple web applications. And that registration can be done with a simple update of the web.config file, rather than having to (potentially) recompile the application to add the functionality. Second, if you’re dealing with a lot of custom event handlers, the global.asax file can become rather convoluted dealing with all the logic necessary to figure out how to deal with each possible scenario. And finally, as an added bonus, I can add modules in places (like SharePoint) where updating the global.asax file may not be an option.
Fortunately, setting up an HTTP module is relatively straight forward. The first thing to do is to create a class that implements IHttpModule. IHttpModule has two very simple methods, Dispose (which you’re probably familiar with), and Init which is where you register your event handlers.
public class CustomerLoggingModule : IHttpModule
{
public void Dispose()
{
// cleanup code if needed
}
public void Init(HttpApplication context)
{
context.BeginRequest +=
new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
// cleanup code if needed
}
}
If you’re curious, there are many, many events you can handle in your HTTP module.
| Event Name | Description |
| BeginRequest | Request has started |
| AuthenticateRequest | Used for creating a custom authentication scheme |
| AuthorizeRequest | Used for any custom authorization scheme – scenarios where you need a bit more logic than simply a list of files that users can access |
| ResolveRequestCache | Determines if a page is in the Output Cache |
| AcquireRequestState | Raised when session state information is retrieved |
| PreRequestHandleExecute | Raised just before the HTTP handler (whatever will actually parse the page) is executed |
| PostRequestHandleExecute | Raised just after the HTTP handler (whatever will actually parse the page) is executed |
| ReleaseRequestState | Raised when the session state information is saved back to the backing store |
| UpdateRequestCache | Raised when the page to the Output Cache |
| EndRequest | One last chance to access any information in the request or page before the result is sent to the user |
The rest is simply adding the appropriate logic to the event handlers. In the example my student asked about, he was looking to log the CustomerID from the query string. While I don’t have the database code to do the logging below, it’s pretty simple to extrapolate how you’d write that out to the database.
public class CustomerLoggingModule : IHttpModule
{
// previous code sampled above
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication) sender;
HttpContext context = application.Context;
String customerID =
context.Request.QueryString["CustomerID"];
if(!String.IsNullOrEmpty(customerID)) {
context.Response.Write("Customer ID : " + customerID);
} else {
context.Response.Write("Customer ID not found");
}
}
}
Finally, we need to update the web.config to register our cool new handler. Fortunately, the DLL for the handler itself can be in the bin directory if we like, although the GAC does work as well.
If IIS 6 is in use (or IIS 7 is running in Classic Mode), the following would need to be added to our web.config:
<system.web>
<httpModules>
<add name="CustomerLoggingModule"
type="HttpModulesPost.CustomerLoggingModule"/>
</httpModules>
</system.web>
For IIS 7 in Integrated Mode (the default for IIS 7), here’s the web.config changes:
<system.webServer>
<modules>
<add name="CustomerLoggingModule"
type="HttpModulesPost.CustomerLoggingModule"/>
</modules>
</system.webServer>
As a side note, I set both in the web.config file for IIS 7. I’ve had a couple issues in the past with SharePoint where it didn’t fire the handler properly if I didn’t have both sections registered, and it also will ensure the code will still execute if someone changes the IIS 7 mode.
And just like that, we’ve now got our own little event handler running behind the scenes, quietly logging our customer information or performing whatever little operations we need.