The ASP Column: HTTP Modules
|
public interface IHttpModule
{
void Dispose();
void Init(HttpApplication context);
}
When an HttpModule is hooked into the pipeline (via an entry in web.config), the ASP.NET runtime calls the module's Init and Dispose methods. Init is called when the module attaches itself to the HttpApplication object and Dispose is called when the module is detached from HttpApplication. The Init and Dispose methods represent the module's opportunity to hook into a variety of events exposed by HttpApplication. These events include the beginning of a request, the end of a request, a request for authentication, and so forth. Notice the HttpApplication parameter passed in to the Init method. Usually, the Init method takes the HttpApplication object and maps event handlers to the desired events.
Figure 2 shows some C# code defining a simple HttpModule that attaches to an application's BeginRequest and EndRequest events to provide simple pre- and post-processing before and after each request. This code is compiled into an assembly that goes into the application's bin directory. To wire this handler up into the processing chain, the web.config file simply declares the module within the httpModules section, as shown here:
<configuration>
<system.web>
<httpModules>
<add type=
"HttpModuleExamples.CustomHttpModule, HTTPModules"
name="CustomHttpModule" />
</httpModules>
</system.web>
</configuration>
<%@ Page Language="C#"%>
The following code shows a plain vanilla ASPX page that uses the HttpModule in the chain:
<html><body><head>
<br>
Hello World! Here's how the HttpModules work...
<br>
<br>
</body> </html>
ASP.NET now routes all requests through the CustomHttpModule's OnBeginRequest method at the beginning of the request, and the OnEndRequest method at the end of the request. A simple ASPX page such as the one in Figure 3 will appear when you surf to the page.
Figure 3 A Simple ASPX Page
BeginRequest and EndRequest aren't the only events you can intercept within an HttpModule. Figure 4 shows all the available events you can route through an HttpApplication and trap within an HttpModule. Catching any of these events is simply a matter of setting up an event handler for the event you want to handle. Figure 5 shows some C# code for an HttpModule intercepting the AuthenticateRequest event.
Terminating Requests Early
One of the most common reasons for intercepting an HTTP request is to terminate the request early if something goes wrong. For example, if you're handling authentication by yourself, you might stop the request if the credentials are incorrect. If you're writing a SOAP server, you may want to discontinue the request if a non-SOAP request comes through. The HttpApplication class has a method named CompleteRequest that finishes the request. You can call CompleteRequest and set the StatusCode and StatusDescription properties of the context object to let the client know about the issue. Figure 6 shows the interception of a request and its completion when the connection is not secure.
System-provided Modules
A good many ASP.NET features are added using this HttpModule technique. These features include output caching, session state, Windows® authentication, forms authentication, Passport authentication, URL authorization, and file authorization. Figure 7 shows these features and the modules responsible for them.
Each of the predefined HttpModules is declared within the host-wide machine.config file, as shown in Figure 8.
The list of HttpModules attached to an app is represented as a collection of IHttpModule references named HttpModuleCollection, which can be accessed as the Modules property of the HttpApplication class. At run time, the collection includes all the system-provided modules declared within machine.config as well as any specified in web.config. The HttpModuleCollection is a list of references to IHttpModule keyed by either the name of the module or an ordinal. You can interrogate the collection to find out which modules are attached, as shown in Figure 9. Figure 10 shows the modules as they're listed on the Web page.
Figure 10 Attached HttpModules
The HttpModules are normally wired up by ASP.NET as the application starts. If you want to manage the modules yourself, you may use the HttpModuleCollection to obtain a reference to any of the modules and call IHttpModule's Init or Dispose methods. Alternatively you might manually load an HttpModule assembly and add the module to the list based upon certain custom criteria for your application.
HttpModules and Global.ASAX
ASP.NET applications may include a global file named GLOBAL.ASAX (known also as the ASP.NET application file). GLOBAL.ASAX lives in the root directory of your ASP.NET application. When the application is loaded at run time, ASP.NET parses the GLOBAL.ASAX file and generates a runtime object derived from HttpApplication. GLOBAL.ASAX is optional, but when it's there, it includes code for responding to application-level events raised by ASP.NET and by HTTP modules.
GLOBAL.ASAX is useful for handling events exposed by the modules that are handling the incoming request. For example, if you wanted to handle authentication within your GLOBAL.ASAX file, you would do so by handling the Application_OnAuthenticateRequest event, as shown here:
<Script language="C#" runat="server">
// Inside GLOBAL.ASAX
void Application_OnAuthenticateRequest(Object Source,
EventArgs Details) {
// Put your authentication code here...
}
</script>
Conclusion
Microsoft has done a great job making sure ASP.NET is extensible. One of the easiest ways to add pre- and post-processing to each request is by chaining an HttpModule into your application. In fact, ASP.NET implements such features as forms authentication and output caching through the HttpModule mechanism. They're easy to write—just create a class derived from IHttpModule, write event handlers for the events you want to intercept, and create an entry into your web.config file to let ASP.NET know about the HttpModule. In future columns I'll explore some of ASP.NET's features, such as output caching and forms authentication, which have been implemented through HTTP modules.
Send questions and comments for George to asp-net@microsoft.com. |
George Shepherd is a software consultant and an instructor with DevelopMentor. George is the coauthor of MFC Internals (Addison-Wesley, 1996), Programming Visual C++ (Microsoft Press, 1998), and Applied .NET (Addison-Wesley, 2001). George may be reached at 70023.1000@compuserve.com. From the May 2002 issue of MSDN Magazine |