programming4us
programming4us
WEBSITE

ASP.NET 3.5 : Writing HTTP Modules (part 1) - The IHttpModule Interface, A Custom HTTP Module

11/22/2012 2:45:56 AM
So we’ve learned that any incoming requests for ASP.NET resources are handed over to the worker process for the actual processing within the context of the CLR. In IIS 6.0, the worker process is a distinct process from IIS, so if one ASP.NET application crashes, it doesn’t bring down the whole server.

ASP.NET manages a pool of HttpApplication objects for each running application and picks up one of the pooled instances to serve a particular request. These objects are based on the class defined in your global.asax file, or on the base HttpApplication class if global.asax is missing. The ultimate goal of the HttpApplication object in charge of the request is getting an HTTP handler.

On the way to the final HTTP handler, the HttpApplication object makes the request pass through a pipeline of HTTP modules. An HTTP module is a .NET Framework class that implements the IHttpModule interface. The HTTP modules that filter the raw data within the request are configured on a per-application basis within the web.config file. All ASP.NET applications, though, inherit a bunch of system HTTP modules configured in the global web.config file.

Generally speaking, an HTTP module can pre-process and post-process a request, and it intercepts and handles system events as well as events raised by other modules. The highly-configurable nature of ASP.NET makes it possible for you to also write and register your own HTTP modules and make them plug into the ASP.NET runtime pipeline, handle system events, and fire their own events.

The IHttpModule Interface

The IHttpModule interface defines only two methods—Init and Dispose. The Init method initializes a module and prepares it to handle requests. At this time, you subscribe to receive notifications for the events of interest. The Dispose method disposes of the resources (all but memory!) used by the module. Typical tasks you perform within the Dispose method are closing database connections or file handles.

The IHttpModule methods have the following signatures:

void Init(HttpApplication app);
void Dispose();

The Init method receives a reference to the HttpApplication object that is serving the request. You can use this reference to wire up to system events. The HttpApplication object also features a property named Context that provides access to the intrinsic properties of the ASP.NET application. In this way, you gain access to Response, Request, Session, and the like.

Table 1 lists the events that HTTP modules can listen to and handle.

Table 1. HttpApplication Events
EventDescription
AcquireRequestState, PostAcquireRequestStateOccurs when the handler that will actually serve the request acquires the state information associated with the request. The post event is not available in ASP.NET 1.x.
AuthenticateRequest, PostAuthenticateRequestOccurs when a security module has established the identity of the user. The post event is not available in ASP.NET 1.x.
AuthorizeRequest, PostAuthorizeRequestOccurs when a security module has verified user authorization. The post event is not available in ASP.NET 1.x.
BeginRequestOccurs as soon as the HTTP pipeline begins to process the request.
DisposedOccurs when the HttpApplication object is disposed of as a result of a call to Dispose.
EndRequestOccurs as the last event in the HTTP pipeline chain of execution.
ErrorOccurs when an unhandled exception is thrown.
PostMapRequestHandlerOccurs when the HTTP handler to serve the request has been found. The event is not available in ASP.NET 1.x.
PostRequestHandlerExecuteOccurs when the HTTP handler of choice finishes execution. The response text has been generated at this point.
PreRequestHandlerExecuteOccurs just before the HTTP handler of choice begins to work.
PreSendRequestContentOccurs just before the ASP.NET runtime sends the response text to the client.
PreSendRequestHeadersOccurs just before the ASP.NET runtime sends HTTP headers to the client.
ReleaseRequestState, PostReleaseRequestStateOccurs when the handler releases the state information associated with the current request. The post event is not available in ASP.NET 1.x.
ResolveRequestCache, PostResolveRequestCacheOccurs when the ASP.NET runtime resolves the request through the output cache. The post event is not available in ASP.NET 1.x.
UpdateRequestCache, PostUpdateRequestCacheOccurs when the ASP.NET runtime stores the response of the current request in the output cache to be used to serve subsequent requests. The post event is not available in ASP.NET 1.x.

All these events are exposed by the HttpApplication object that an HTTP module receives as an argument to the Init method.

A Custom HTTP Module

Let’s begin coming to grips with HTTP modules by writing a relatively simple custom module named Marker that adds a signature at the beginning and end of each page served by the application. The following code outlines the class we need to write:

using System;
using System.Web;

namespace Core35.Components
{
    public class MarkerModule : IHttpModule
    {
        public void Init(HttpApplication app)
        {
            // Register for pipeline events
        }

        public void Dispose()
        {
            // Nothing to do here
        }
    }
}

The Init method is invoked by the HttpApplication class to load the module. In the Init method, you normally don’t need to do more than simply register your own event handlers. The Dispose method is, more often than not, empty. The heart of the HTTP module is really in the event handlers you define.

Wiring Up Events

The sample Marker module registers a couple of pipeline events. They are BeginRequest and EndRequest. BeginRequest is the first event that hits the HTTP application object when the request begins processing. EndRequest is the event that signals the request is going to be terminated, and it’s your last chance to intervene. By handling these two events, you can write custom text to the output stream before and after the regular HTTP handler—the Page-derived class.

The following listing shows the implementation of the Init and Dispose methods for the sample module:

public void Init(HttpApplication app)
{
    // Register for pipeline events
    app.BeginRequest += new EventHandler(OnBeginRequest);
    app.EndRequest += new EventHandler(OnEndRequest);
}

public void Dispose()
{
}

The BeginRequest and EndRequest event handlers have a similar structure. They obtain a reference to the current HttpApplication object from the sender and get the HTTP context from there. Next, they work with the Response object to append text or a custom header:

public void OnBeginRequest(object sender, EventArgs e)
{
    HttpApplication app = (HttpApplication) sender;
    HttpContext ctx = app.Context;

    // More code here
    ...

    // Add custom header to the HTTP response
    ctx.Response.AppendHeader("Author", "DinoE");

    // PageHeaderText is a constant string defined elsewhere
    ctx.Response.Write(PageHeaderText);
}

public void OnEndRequest(object sender, EventArgs e)
{
    // Get access to the HTTP context
    HttpApplication app = (HttpApplication) sender;
    HttpContext ctx = app.Context;

    // More code here
    ...

    // Append some custom text
    // PageFooterText is a constant string defined elsewhere
    ctx.Response.Write(PageFooterText);
}


					  

OnBeginRequest writes standard page header text and also adds a custom HTTP header. OnEndRequest simply appends the page footer. The effect of this HTTP module is visible in Figure 1.

Figure 1. The Marker HTTP module adds a header and footer to each page within the application

Registering with the Configuration File

You register a new HTTP module by adding an entry to the <httpModules> section of the configuration file. The overall syntax of the <httpModules> section closely resembles that of HTTP handlers. To add a new module, you use the <add> node and specify the name and type attributes. The name attribute contains the public name of the module. This name is used to select the module within the HttpApplication’s Modules collection. If the module fires custom events, this name is also used as the prefix for building automatic event handlers in the global.asax file:

<system.web>
  <httpModules>
    <add name="Marker"
         type="Core35.Components.MarkerModule,Core35Lib" />
  </httpModules>
</system.web>

The type attribute is the usual comma-separated string that contains the name of the class and the related assembly. The configuration settings can be entered into the application’s configuration file as well as into the global web.config file. In the former case, only pages within the application are affected; in the latter case, all pages within all applications are processed by the specified module.

The order in which modules are applied depends on the physical order of the modules in the configuration list. You can remove a system module and replace it with your own that provides a similar functionality. In this case, in the application’s web.config file you use the <remove> node to drop the default module and then use <add> to insert your own. If you want to completely redefine the order of HTTP modules for your application, you can clear all the default modules by using the <clear> node and then re-register them all in the order you prefer.

Note

HTTP modules are loaded and initialized only once, at the startup of the application. Unlike HTTP handlers, they apply to just any requests. So when you plan to create a new HTTP module, you should first wonder whether its functionality should span all possible requests in the application. Is it possible to choose which requests an HTTP module should process? The Init method is called only once in the application’s lifetime; but the handlers you register are called once for each request. So to operate only on certain pages, you can do as follows:

public void OnBeginRequest(object sender, EventArgs e)
{
    HttpApplication app = (HttpApplication) sender;
    HttpContext ctx = app.Context;
    if (!ShouldHook(ctx))
         return;
    ...
}

OnBeginRequest is your handler for the BeginRequest event. The ShouldHook helper function returns a Boolean value. It is passed the context of the request—that is, any information that is available on the request. You can code it to check the URL as well as any HTTP content type and headers.


Accessing Other HTTP Modules

The sample just discussed demonstrates how to wire up pipeline events—that is, events fired by the HttpApplication object. But what about events fired by other modules? The HttpApplication object provides a property named Modules that gets the collection of modules for the current application.

The Modules property is of type HttpModuleCollection and contains the names of the modules for the application. The collection class inherits from the abstract class NameObjectCollectionBase, which is a collection of pairs made of a string and an object. The string indicates the public name of the module; the object is the actual instance of the module. To access the module that handles the session state, you need code like this:

SessionStateModule sess = app.Modules["Session"];
sess.Start += new EventHandler(OnSessionStart);

As mentioned, you can also handle events raised by HTTP modules within the global.asax file and use the ModuleName_EventName convention to name the event handlers. The name of the module is just one of the settings you need to define when registering an HTTP module.

Other  
 
 
Video tutorials
- How To Install Windows 8

- How To Install Windows Server 2012

- How To Install Windows Server 2012 On VirtualBox

- How To Disable Windows 8 Metro UI

- How To Install Windows Store Apps From Windows 8 Classic Desktop

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010
programming4us programming4us
programming4us
 
 
programming4us