Implementing an IIS Application Filter Using .NET HttpModules and Response Filtering (cont'd)
HttpModule—the Filter for all Requests (cont'd)
One important point still needs to be clarified. In the preceding paragraph, where the workings of the WebFilter class are described, I made numerous references to the current request. Knowing as we do, that a single instance of the WebFilter filters every single request for the entire application, how, for any given event, do we identify the context of the current request? If WebFilter is assembling the page footer for User A, and an OnBeginRequest event is raised for a request coming in from User B, how do we keep from writing User B’s header into User A’s response? And vice versa?

As it turns out, this is a relatively trivial factor, which is greatly simplified by the .NET Framework environment. The fact is, at any given time, code inside of an HttpModule has access to the context of the request which is currently being operated on, with one simple statement:

C#
HttpContext httpCtx = HttpContext.Current;

VB.NET
Dim httpCtx As HttpContext = HttpContext.Current
advertisement

That’s it—simple! Of course, we still need to keep in mind that a single class instance of WebFilter serves as the HttpModule to filter all application requests. Request specific data should never be stored in a class member variable because at any given time an event from a different request might be raised. If you need to preserve data from the beginning of the request (OnBeginRequest) to the end of the request (OnPostRequestHandlerExecute), the most logical place to put it would be in the Session object.

So let’s recap; I’ve installed an HttpModule to monitor all application requests. At the start of a request the page header is assembled inside of the HttpModule. Then control proceeds to the HttpHandler which returns the main page content section. After the HttpHandler is done, the footer is assembled inside the HttpModule. And then the entire page is written back to the browser. Not bad. But there’s still one critical feature which is missing.

Since the header and footer are pre-pended and appended to the response stream returned by the HttpHandler it is easy to accomplish this inside the HttpModule. But what if we actually want to modify the response stream which is returned by the HttpHandler? And here’s why I’d want to do that. I perform a particular XSL transformation in order to format the menu on each page. In order to free page developers from having to worry about this, I’d like to implement this in my application controller. All the page designer needs to do is insert the string {menu} somewhere into the HTML output and the menu will be rendered into the designated location. Similarly, in some of the pages, developers simply encode the string {tabs} in order to have a context sensitive tabstrip rendered in place. In order to do this though, we need some way of accessing the response stream from the HttpHandler. However, although the HttpModule is notified when the HttpHandler has completed, it does not get access to the response data output from the HttpHandler.

That’s the bad news. The good news is, that there is a facility which will enable us to do this. It’s called response filtering and we use the Response.Filter property in order to implement it.

Take a look at the Response object and you’ll see that it has a Filter property. As described in the object browser, the Filter gets or sets a wrapping filter object used to modify the HTTP entity body before transmission’. This is exactly what we need to do in order to make modifications to the HTML output of the HttpHandler. The Filter property is declared as type System.IO.Stream. In order to assign our own class to this filter property we need to define our class as inheriting from System.IO.Stream:

C#
public class PageFilter : System.IO.Stream

VB.NET
Public Class PageFilter : Inherits System.IO.Stream

We now have a Stream class, PageFilter, which can be assigned to the Response.Filter property. By attaching PageFilter to the Response.Filter property, PageFilter will be notified at critical times as data is written to the Response buffer. The most significant event of course is the Write operation. When this method is called, you’ll have the opportunity to modify data as it’s being written to the Response buffer. (I combine this with 'Response.Buffer = true' so that my PageFilter receives the complete response stream in a single method invocation.):

C#
public override void Write(byte[] buffer, int offset, int count)

VB.NET 
Public Overrides Sub Write(ByVal buffer() As Byte, _
                           ByVal offset As Integer, _
                           ByVal count As Integer)

I’m not going to present extensive code samples here on how to implement your stream class, since I’ll present a link below to the on-line documentation which you can use as a guide. I’d like to explain though, a few basics on how to use the Response filter within the context of the HttpModule application controller.

In the HttpModule, at the start of the request (I do it in OnBeginRequest) simply attach your HTTP response filter by assigning a new instance to Response.Filter:

C#
httpCtx.Response.Filter = 
   new PageFilter(httpCtx.Response.Filter, 
                  m_XNav, 
                  m_XMenu, 
                  m_XTabs, 
                  Section, 
                  Tabstrip, 
                  Page);

VB.NET
httpCtx.Response.Filter = _
   New PageFilter(httpCtx.Response.Filter, _
                  m_XNav, _
                  m_XMenu, _
                  m_XTabs, _
                  Section, _
                  Tabstrip, _
                  Page)

As described above, httpCtx represents a reference to HttpContext.Current, which is the context for the current request. By attaching our filter to the httpCtx.Response.Filter, we are attaching an instance of our own HTTP filter class to the response for the current request. This is significant.

Although a single HttpModule intercepts all application requests, at any given time multiple HttpContext objects will exist, with each instance dedicated to a specific request. Each of these instances will have a Response object which is dedicated to a specific request, and each Response object has a Filter property which is set to reference an instance of the PageFilter class which is dedicated to a particular request. So just to emphasize, unlike the HttpModule class WebFilter, the PageFilter class is dedicated to a specific request for its entire lifespan. Because this is so, we can include specific request relevant information at the time the class is constructed. This is critical because the PageFilter Write method is an override of the Write method specified in the base Stream class. This method definition doesn’t provide us with any way of supplying this context specific information at the time that the response stream is being written. Consequently, we preload’ this information by supplying these parameters on the class constructor. Since the PageFilter is dedicated to a specific Response object for a specific request, it is completely acceptable to store this data in class member variables and to subsequently use these variables to provide information regarding the current request context when the Write method is called.

This rounds out our ability to filter all aspects of each application request. In our HttpModule (i.e. the WebFilter class) we have the ability to perform pre-processing and post-processing at various stages in the request lifespan. In addition, by implementing a Stream derived PageFilter class, we are able (via Response.Filter) to hook into the response stream and actually make modifications to data written to the response buffer, including data which is output by the HttpHandler. The following is a basic outline of the complete processing sequence.

HttpModule (Web Application Filter) Processing Sequence


I hope this article has been useful in explaining the basic HttpModule processing model and how it differs from its counterpart, the HttpHandler. I found the following links to be extremely helpful toward the coding of my implementation and I am sure that you will find these useful as well.

MSDN—The ASP Column—HTTP Modules by George Shepherd
(Includes a C# code download which I found to be extremely useful.)

DevX—Extending ASP.NET with HttpHandlers and HttpModules by Bipin Joshi
(Includes useful VB.NET examples)

Microsoft Knowledge Base Article - 307996
HOW TO: Create an ASP.NET HTTP Module Using Visual C# .NET


Microsoft Knowledge Base Article - 308000
HOW TO: Create an ASP.NET HTTP Module Using Visual Basic .NET


MSDN—IHttpModule Interface Definition

MSDN—IHttpApplication Class Definition
(Provides a listing of the sequence of events which occur during the processing of a request.)

MSDN—HttpResponse.Filter Property
(Includes excellent VB.NET and C# code samples which demonstrate how to implement a Response Filter.)


Previous Page: HttpModule--the Filter for All Requests  
Joseph Geretz is the founder of Focal Point Solutions, Inc., a consulting firm serving clients in the New York metropolitan area. He has been working with Microsoft technologies, since 1994 (back when COM was called OLE). His primary focus these days is on n-tier systems, using Microsoft .NET technologies. His development language of choice these days is C#, although he still uses VB.NET from time to time and has fond memories of VB6 and even COBOL, from an earlier, more stateless era. Joseph can be reached at j.geretz@FPSNow.com.
Page 1: IntroductionPage 3: HttpModule--the Filter for all Requests (cont'd)
Page 2: HttpModule--the Filter for All Requests