|
ASP.NET provides a robust framework
for your Web applications. However, at times it becomes necessary
to go beyond the out-of-the-box functionality.
For example, when you request a resource such as
an HTML page or ASP page using the browser, IIS processes that resource
based on its file extension. IIS processes ASP pages using a DLL
named asp.dll. Similarly, IIS processes ASP.NET (.aspx) pages with
the aspnet_isapi.dll. But sometimes you may need to process custom
file extensions.
One of the goals of ASP.NET was to allow you to
do everything you could potentially conceive of related to Web programming
directly in the product. It shouldn't limit you. To that end, Microsoft
added two new concepts: HttpModules and HttpHandlers. These did
not exist inside of ASP. To find analogous functionality, you had
to step outside into the world of ISAPI programming. HttpModules
and HttpHandlers in ASP.NET are fairly similar to ISAPI filters,
but they implement slightly different functionality.
ISAPI is an important technology that allows us
to enhance the capabilities of an ISAPI-compliant Web server (IIS
is an ISAPI-compliant Web server). The following components serve
this purpose:
- ISAPI Extensions
- ISAPI Filters
ASP .NET Request Processing
ASP.NET request processing is based on a pipeline
model in which ASP.NET passes http requests to all the http modules
in the pipeline. Each http module receives the http request and
has full control over it. The http module can play with the request
in any way it sees fit. Once the request passes through all of the
http modules, it is eventually served by an http handler. The http
handler performs some processing on it, and the result again passes
through the http modules in the pipeline. The following figure describes
this flow.

Notice that during the processing of an http request,
only one HTTP handler will be called, whereas more than one HTTP
modules can be called.
ASP.Net Request Handling
To understand how HttpModules and HttpHandlers fit
into the scheme of things, you have to understand the way that ASP.NET
handles a request. When a request is received by Internet Information
Server (IIS), it looks at the extension to determine which ISAPI
filter should handle the request. For any of the supported file
extensions, such as .aspx or .asmx, the answer is aspnet_isapi.dll.
When ASP.NET fires up, it performs almost the same process again.
It looks at the request and compares it to the <httpHandlers>
section of the .config file. By default, machine.config maps .aspx
files to the PageHandlerFactory and .asmx files to the WebServiceHandlerFactory.
This mapping determines the HttpHandler (class) that is responsible
for handling the request. With the concept of mapping, you can create
a new HttpHandler and map it to a new type of request. In fact,
this is exactly what Microsoft did with Trace.axd. You will find
that it is a new HttpHandler that is registered in machine.config
for any request path that ends in trace.axd.
While processing a request received from IIS, ASP.NET
raises several events. They are raised in the following order:
1. BeginRequest
2. AuthenticateRequest
3. AuthorizeRequest
4. AcquireRequestState
5. ResolveRequestCache
6. Page Constructor
7. PreRequestHandlerExecute
8. Page.Init
9. Page.Load
10. PostRequestHandlerExecute
11. ReleaseRequestState
12. UpdateRequestCache
13. EndRequest
14. PreSendRequestHeaders
15. PreSendRequestContent
From a programmer's point of view, HttpHandlers
and HttpModules are nothing but classes that implement certain interfaces.
HttpHandlers must implement the IHttpHandler interface. Some built-in
classes such as HttpApplication and Page already implement the IHttpHandler
interface. Similarly, new HttpModule-derived classes must implement
the IHttpModule interface. Again, the Framework contains built-in
classes such as FormsAuthenticationModule and WindowsAuthenticationModule
that already implement the IHttpModule interface. Both interfaces
reside in the System.Web namespace.
Http Handlers
HTTP handlers are the .NET components that implement
the System.Web.IHttpHandler interface. Any class that implements
the IHttpHandler interface can act as a target for the incoming
HTTP requests. HTTP handlers are somewhat similar to ISAPI extensions.
The interface consists of a read only property named IsReusable,
which returns a Boolean value (typically true) indicating whether
another request can use the IHttpHandler instance, and a ProcessRequest
method, which takes a parameter of type HttpContext and performs
the job of handling the extension.
I used VB.NET for the sample code, but you can use
the .NET language of your choice. First, launch VS.NET, create an
empty project (in the sample code), and add a new class to it. Add
a reference to the System.Web namespace and add an Imports
System.Web statement at the top of the class file. Add an
Implements statement to add the IHttpHandler interface.
| Imports
System
Imports System.Web
Public
Class ClsHttpHandlers
Implements IHttpHandler
Public ReadOnly Property
IsReusable() As Booleanw
Implements System.Web.IHttpHandler.IsReusable
Get
Return
Truet
End Get
End Property
Public Sub ProcessRequest(ByVal context
As
System.Web.HttpContext) Implements
System.Web.IHttpHandler.ProcessRequests
context.Response.Write
_
("<html><body><h3>
Your request is handled by
ClsHttpHanlders " & _
"</h3></body></html>")
End Sub
End Class |
Configuring the HttpHandler in IIS
After you develop an HttpHandler or HttpModule you
must configure IIS and ASP.NET for the new code to take effect.
There are actually two steps involved in running a custom HttpHandler.
First, you use the IIS Application Configuration dialog to map the
file extension to the ASP.NET engine. Second, you modify the configuration
sections in the application's web.config file to specify the namespace
and class you want to use to handle that extension. Since we are
creating a handler for handling files of a new extension, we also
need to tell IIS about this extension and map it to ASP.NET. If
we don't perform this step and try to access the .hand file,
IIS will simply return the file rather than pass it to ASP.NET runtime.
As a consequence, the HTTP handler will not be called.
For IIS, you add the required file extension in
the Application Configuration dialog as shown in following figure.
You can add or remove handlers using this dialog.

The dialog associates a specific file extension
with a specific handler-in this case, tell IIS to use the ASP.NET
engine (aspnet_isapi.dll). Following figure shows how to fill in
the dialog for the example. Set the Executable field to the location
of the aspnet_isapi.dll file on your server (your path may vary
from the path shown in the figure). Fill in the Extension field
with .hand.

Configuring the HttpHandler in Web.config
ASP.NET maintains its configuration information
in the following configuration files:
Machine.config file contains the configuration
settings that apply to all the Web applications installed on that
box. Web.config file is specific to each Web application. Each Web
application can have its own web.config file. Any sub directory
of a Web application may have its own web.config file; this allows
them to override the settings imposed by the parent directories.
We can use <httpHandlers> and <add>
nodes for adding HTTP handlers to our Web applications. In fact
the handlers are listed with <add> nodes in between <httpHandlers>
and </httpHandlers> nodes. Here is a generic example of adding
an HTTP handler:
<httpHandlers>
<add
verb="supported http verbs" path="path"
type="namespace.classname,
assemblyname" />
<httpHandlers>
In the above XML,
The verb attribute specifies the HTTP verbs supported
by the handler. If the handler supports all of the HTTP verbs, simply
use "*", otherwise list the supported verbs in a comma
separated list. So if your handler supports only HTTP GET and POST,
then verb attribute will be "GET, POST".
The path attribute specifies the path or wildcard
specification of the files for which this handler will be invoked.
For example, if you want your handler to be called only when test.xyz
file is requested, then the path attribute will contain "test.xyz";
similarly if you want your handler called for any file having .xyz
extension, the path attribute will contain "*.xyz" ( *.hand
in our case).
The type attribute specifies the actual type of
the handler or handler factory in the form of a combination of namespace,
class name and assembly name. ASP.NET runtime first searches the
assembly DLL in the application's bin directory and then searches
in the Global Assembly Cache (GAC).
Next, to configure ASP.NET to recognize new handlers
and modules, you modify two configuration sections in the web.config
file for your application: the <httpHandlers> section, and
the <httpModules>; section.
To test the sample HttpHandler you first need to
create a new Web project with VS.NET. Next, open the web.config
file of the new application and locate the <httpHandlers>
section. ASP.NET uses the <httpHandler> section to specify
mappings between file extensions and the appropriate HttpHandler.
The section will already contain some handlers, for example, the
following fragment shows the <httpHandlers> section on my
machine :
<httpHandlers>
<add verb="*" path="*.chart"
type="MyHttpHandler.ChartHandler,MyHttpHandler" />
<add verb="*" path="*.vb"
type="System.Web.HttpNotFoundHandler,System.Web" />
<add verb="*" path="*.cs"
type="System.Web.HttpNotFoundHandler,System.Web" />
<add verb="*" path="*.vbproj"
type="System.Web.HttpNotFoundHandler,System.Web" />
<add verb="*" path="*.csproj"
type="System.Web.HttpNotFoundHandler,System.Web" />
<add verb="*" path="*.webinfo"
type="System.Web.HttpNotFoundHandler,System.Web" />
</httpHandlers>
For our example, you need to add httphandlers like
this
<httpHandlers>
<add verb="*" path="*.hand"
type="HttphandlersAsm.ClsHttpHandlers,HttphandlersAsm"
/>
</httpHandlers>
Save your changes. Next, add a new file with the extension .hand
to the Web application. Navigate to this file from your Web browser,
you should see the following page.

HTTP Modules
An HTTP module is a class that contains code that
executes whenever someone makes a request for a page in your ASP.NET
application. Because a module executes each and every time someone
makes a request for a page, modules are perfect for implementing
functionality such as caching, authentication, and state management.
HTTP modules are .NET components that implement
the System.Web.IHttpModule interface. These components plug themselves
into the ASP.NET request processing pipeline by registering themselves
for certain events. Whenever those events occur, ASP.NET invokes
the interested HTTP modules so that the modules can play with the
request. So you can write your http modules for the events which
is mentioned already in request handling chapter.
An HTTP module is supposed to implement the following
methods of the IHttpModule interface:
- Init : This method allows an HTTP module to register
its event handlers to the events in the HttpApplication object.
- Dispose :This method gives HTTP module an opportunity
to perform any clean up before the object gets garbage collected.
An HTTP module can register for the following events
exposed by the System.Web.HttpApplication object.
BeginRequest, AuthenticateRequest, AuthorizeRequest,
AcquireRequestState, ResolveRequestCache, Page Constructor, PreRequestHandlerExecute,
Page.Init, Page.Load, PostRequestHandlerExecute, ReleaseRequestState,
UpdateRequestCache, EndRequest , PreSendRequestHeaders, PreSendRequestContent
BeginRequest is the first event to fire when processing
a request. EndRequest is almost the last event to fire. Let's write
an HttpModule that sinks these events and uses them to time stamp
the output HTML with the time that the request began processing
and when it finished processing. This information might be useful
if you were trying to profile a group of pages.
We will create this as our first HttpModule. First,
we need to create a class. This class will implement the IHttpModule
interface. To implement this interface, we need to supply two members:
Init and Dispose. When ASP.NET loads our HttpModule to participate
in processing a request, a reference to the HttpApplication object
is passed to the Init method.
After we have implemented IHttpModule, we can get
into doing the things that are specific to our task. In this example,
we need to create event handlers for BeginRequest and EndRequest.
We do this by first creating our sub procedure like this:
Public
Sub SubBeginReq(ByVal s As Object, ByVal e As EventArgs)
Next we need to wire them up in the Init method
that is part of the IhttpModule interface like this:
AddHandler
context.BeginRequest, AddressOf SubBeginReq
The complete HttpModule is shown below:
|
Imports System
Imports System.Web
Imports System.Web.Caching
Public
Class ClsHttpMod
Implements IHttpModule
' Register Event
Handlers
Public Sub Init(ByVal
context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
AddHandler context.BeginRequest,
AddressOf SubBeginReq
AddHandler context.EndRequest,
AddressOf SubEndReq
End Sub
Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
End
Sub
Public Sub SubBeginReq(ByVal s As Object,
ByVal e As EventArgs)
Dim app As HttpApplication
app = CType(s, HttpApplication)
app.Response.Write _
("<h4>Request Begins Here...
(ClsHttpMod)</h4>")
End
Sub
Public Sub SubEndReq(ByVal s As Object,
ByVal e As EventArgs)
Dim app As HttpApplication
app = CType(s, HttpApplication)
app.Response.Write _
("<h4>Request Ends Here...(ClsHttpMod)</h4>")
End
Sub
End Class |
Registering HTTP Modules in Configuration Files
Once an HTTP module is built and copied into the
bin directory of our Web application or copied into the Global Assembly
Cache, then we will register it in either the web.config or machine.config
file.
We can use <httpModules> and <add> nodes
for adding HTTP modules to our Web applications. In fact the modules
are listed by using <add> nodes in between <httpModules>
and </httpModules> nodes.
Since configuration settings are inheritable, the
child directories inherit configuration settings of the parent directory.
As a consequence, child directories might inherit some unwanted
HTTP modules as part of the parent configuration; therefore, we
need a way to remove those unwanted modules. We can use the <remove>
node for this.
If we want to remove all of the inherited HTTP modules
from our application, we can use the <clear> node. The following
is a generic example of adding an HTTP module:
<httpModules>
<add type="classname,
assemblyname" name="modulename" />
<httpModules>
The following is a generic example of removing an
HTTP module from your application.
<httpModules>
<remove name="modulename"
/>
<httpModules>
In the above XML,
The type attribute specifies the actual type of
the HTTP module in the form of class and assembly name. The name
attribute specifies the friendly name for the module. This is the
name that will be used by other applications for identifying the
HTTP module.
For our example , you need to add the following
code:
<httpModules>
<add type="HttpModulesAsm.ClsHttpMod,HttpModulesAsm"
name="ClsHttpMod" /
</httpModules>
Save your changes. Next, add a new file with the extension .hand
to the Web application. Navigate to this file from your Web browser,
you should see the following page.

Using the test form, any controls or HTML markup
you add to the form would appear between the two lines written by
the MyBeginRequest and MyEndRequest events.
Of course, you might not want to have your HttpModule classes write
output, but the example serves to show that the sample works as
expected, trapping the BeginRequest and EndRequest events and processing
the request .
Conclusion
As you might have realized with HTTP handlers and
HTTP modules, ASP.NET has put a lot of power in the hands of developers.
Plug your own components into the ASP.NET request processing pipeline
and enjoy the benefits. This article should at least get you started
with these components. Now you can build custom HttpHandlers to
process requests with specific file extensions or to process one
particular request, or create custom HttpModules to filter or manipulate
requests, either before or after the ASP.NET engine processes the
request.
|