
n this article, I will concentrate on the critical differences in the processing model implemented by HttpHandlers versus that implemented by HttpModules.
I'll be presenting specific coding samples as necessary in
order in order to illustrate various points, but I won't be
presenting a comprehensive sample of my own
implementation. A wealth of information and code samples are available to demonstrate how to establish an HttpModule to participate in your application’s web
requests and I’ll present these links toward the end of the
article. In the meantime, It's my hope that this article will
complement the existing samples and documentation and assist
you with the development of your own IIS Application filtering
solution.
| If you’ve worked with ISAPI filters under IIS4, the HttpModule processing model is probably nothing new to you. However ISAPI filtering under IIS4 was relatively out-of-bounds for VB developers and therefore the
fundamental processing model may be less than intuitive to many VB
developers. |
|
HttpHandlerthe Target for your Request
The HttpHandler model is relatively easy to understand. An HttpHandler is the target of a web request. In fact, a WebForm (.aspx) page derives from System.Web.UI.Page which implements the HttpHandler interface. Check it out in the object browser.
So as far as the
processing model is concerned, writing your own HttpHandler is
no different than writing a WebForm page or any other .aspx
(or .asp) script. As with these scripts, the context of each
web request is made available to the HttpHandler on a
request-by-request basis. This context will include the global
Server and Application objects as well as the Request,
Response and Session objects which are relevant to the current
request.
An HttpHandler is created specifically (or retrieved from the
pool) for each request and is dedicated exclusively to that
request for the remainder of its lifetime (or until it is
released back to the pool). The active lifetime for each
particular request begins when control enters
ProcessRequest, and extends until control exits ProcessRequest.
During this time, request specific data may be freely
accumulated and cached globally since the entire scope of the
active lifetime is dedicated to a specific request.
Note the IsReusable property defined in the IHttpHandler
interface. If this is returned as true, then the HttpHandler
will not be destroyed when control exits ProcessRequest.
Rather, it will be released to the pool for use by a future
requestor. Naturally, this means that request specific data
must be de-initialized at the end of a request, or
reinitialized at the beginning of a request. (Cautious
developers may elect to initialize at both points.) This
consideration is standard to object pooling in general and is
not specific to HttpHandlers.
In my previous article, I described how I used an HttpHandler
in order to implement a centralized request controller for my
.NET web application. See that
article for more details, but the basic strategy is to map
all requests to a particular HttpHandler. That HttpHandler
uses information coming in from the browser (e.g. QueryString,
Cookie) in order to create and call the relevant handler
class. The benefit of this model is that common pre-processing
and post-processing can be centralized to the HttpHandler
application controller. This guarantees that the relevant
pre-processing and post-processing must be called for every
request. It also means that when either of these request stages need to be modified, the change can be
effected to a central location which will immediately impact
all requests across the entire application.
The HttpHandler approach is a robust model for
implementing a web application where request handlers are
implemented as compiled classes which implement a common
interface. As mentioned earlier, the HttpHandler instantiates
the correct class for the current request and calls the
defined interface method. The HttpHandler approach is less
helpful though, if we’d like to take advantage of the RAD
features offered by Visual Studio .NET and WebForms for rapid
web application development.
As HttpHandlers, WebForms are designed to be invoked directly
as the target of a browser request. However, using the
centralized HttpHandler as an application controller means
that all requests are mapped to that particular WebHandler. At
this point, the application controller WebHandler (and not the
WebForm script) becomes the target of the HTTP request. This
becomes a significant barrier to WebForms style development.
I recently worked on a project where the rules changed midway
through development. Initially, the developers who had come
from a VB6/ASP background were quite amenable to the prospects
of implementing the application request handlers as compiled
classes. However, after seeing the brand new capabilities of
.NET WebForms they decided that they just could not commit to
a long-term restriction against the use of WebForms to develop
application request handlers. Since WebForm facilities are
based on the fundamentals of HTTP (query parameters, cookies
and form fields) it is certainly possible, using the
System.NET classes, to write code to issue a secondary request
to, and to receive the response from, the .NET WebForm for
those requests which are implemented as WebForms. Ultimately
though, this would be a lot of work and tantamount to
rewriting the web server! Fortunately, there is a counterpart
mechanism, the HttpModule which allows us to impose
centralized application-wide request processing without
interfering with the target of the request emanating from the
browser.
Before moving on to the HttpModule, I’d like to just
re-emphasize the limitation presented by HttpHandler. Since
the HttpHandler becomes the target of the request, it is
difficult to engineer the application controller as an
HttpHandler in an environment where the application request
handlers are themselves implemented as HttpHandlers (as is the
case with WebForms). This is not a flaw in the HttpHandler
implementation; On the contrary, the HttpHandler is
specifically designed to fulfill
the role of a request handler, rather than an
application controller. In order to implement an application
controller which can filter every application request,
without disturbing the target HttpHandler for that request, we
need to take a look at the HttpModule.