As you might expect, there is much more to this topic than
I can cover in this article. To learn more about handlers and
how they fit into the rest of the ASP.NET development model,
you will want to pick up a copy of Developing
Microsoft ASP.NET Server Controls and Components by Nikhil
Kothari and Vandana Datye. Besides explaining the ins and outs
of extending the functionality of ASP.NET by creating custom
server controls, they include an entire chapter devoted to
HTTP handlers. To get a feel for the book, you can review the
table
of contents and even read a sample chapter on Developing
a Simple Custom Control.
HTTP Handler Architecture
HTTP handlers provide two key benefits over the standard
ASP.NET development model. First off, handlers provide you
with greater control over the actual interaction with the
client because they give you direct access to the raw HTTP
requests. For example, if your client application is not a
browser but rather some arbitrary application, you can send
just the data it needs. This way, the client app does not need
to worry about extracting the data from all the noise that
makes up a typical HTML response. The second benefit is
performance. With HTTP handlers, you will see a bit of a
performance gain over standard ASPX files because you can
bypass some overhead, including the Page class which all Web
Forms must inherit.
If you are familiar with ISAPI development, you'll see that
an HTTP handler is very similar to an ISAPI Extension. Astute
readers may wonder why I think HTTP handlers are such a big
deal given that ISAPI has been around since the IIS 2.0
days-and that was a long time ago. The simple answer
is: ISAPI development is hard. To write an ISAPI application,
you need to be a pretty accomplished C++ programmer who is
comfortable developing multi-threaded server applications.
Debugging ISAPI apps is notoriously difficult, and minor
coding mistakes can quickly lead to memory leaks and unhandled
exceptions that crash your application. To make matters even
worse, because ISAPI filters run in the same memory space as
the Web server itself, such errors will often bring down the
entire Web server.
HTTP handlers, on the other hand, are written in managed
code, so you gain the benefits provided by the .NET Framework
and CLR such as easy debugging, type safety, garbage
collection, and the Base Class Libraries.
Enough talk-let's look at the code.
Writing a Simple HTTP handler
At its most basic level, an HTTP handler is nothing more
than a class that implements the IHttpHandler
interface. The following example shows a very simple HTTP
handler written in C#:
<% @ webhandler
language="C#" class="SimpleHandler" %>
using System;
using System.Web;
public class
SimpleHandler: IHttpHandler { public bool
IsReusable { get { return false; } }
public
void ProcessRequest(HttpContext ctx) {
ctx.Response.Write("Hello, I'm a simple
handler"); } }
Let's walk the steps required to execute this handler. The
first step is to create a new file called SimpleHandler.ashx
and drop it in your Web root. Note that the ASHX extension
signifies that the file represents an HTTP handler. Later on,
I'll show you how the Web server makes this association but
for the time being the specifics are not important. You will
want to start off with the webhandler directive
that tells ASP.NET that the file contains an HTTP handler and
the class
directive specifies the class that implements it, in this
example SimpleHandler.
Now it's time to write the handler itself. To do this you
create the class SimpleHandler and
implement the IHttpHandler
interface from the System.Web namespace.
The interface itself is extremely simple; you need to
implement only two things: the IsReusable property,
which is read-only, and the ProcessRequest
method, which does the heavy lifting. To keep things simple,
keep the IsReusable property
as false.
You'll notice that ProcessRequest
receives a single argument, which is an HttpContext class.
This class provides access to the intrinsic server objects
such as Request, Response, and Server. This sample
uses the Response object's Write() method to
send some test back to the client app. For the complete
documentation of IHttpHandler
interface, see the online documentation on
MSDN®.
That's all it takes to write a simple HTTP handler.
Writing a Custom HTTP Handler
As it turns out, the process for writing a custom handler
is nearly identical to writing a simple one. The only real
differences are that you create the class in your own
namespace and don't include the directive syntax as shown in
this example of a more complex handler:
using
System; using System.Web;
namespace
Mauvais.Samples.MSPress { public class
ComplexHandler : IHttpHandler
{ public bool
IsReusable { get { return false; }
}
public
void ProcessRequest(HttpContext ctx) {
string url =
ctx.Request.RawUrl; int
ext = url.ToLower().LastIndexOf(".mspress" ) -1 ;
ctx.Response.Write("Hello,
" + url.Substring(1, ext) + "!");
}
} }
This code simply strips the .mspress extension off the raw
ULR and echoes it back.
With the code being so similar, the main difference between
the two is in the implementation. A simple handler is bound to
a specific file name such as SimpleHandler.ashx
while a custom handler is bound to a file pattern. In other
words, the only way to access your simple handler is
http://localhost/SimpleHandler.ashx. On the other hand, you
can execute a custom handler by referencing any URL that
matches the file pattern to which your handler is bound. For
example, if you bind your handler to the .mspress extension,
either of the following URLs would work:
http://localhost/Scott.mspress or
http://localhost/Dave.mspress.
As I mentioned earlier, ASP.NET automatically knows that
files with a .ASHX extension are implemented as handlers. The
reason for this is two-fold. First, when you install the .NET
Framework, it adds an application extension mapping to IIS
which associates .ashx with aspnet_isapi.dll. Second,
machine.config specifically maps the .ASHX extension to the
System.Web.UI.SimpleHandlerFactory
class. If you look through the section of
machine.config, you will see that many common ASP.NET
extensions such as .aspx, .asmx, and trace.axd are implemented
as handlers. Even more interesting, extensions for sensitive
files such as .config, .vb, and .cs are mapped to a class
called System.Web.HttpForbiddenHandler
which prevents those files from being downloaded.
To configure your server to use your handler for requests
ending in .mspress, you need to compile and deploy your code,
add an entry in your web.config to associate .mspress with
your class, and configure a new application extension in
IIS.
To test this, compile the code of the complex handler
example and copy the DLL to the Bin directory off your Web
root. Next you will want to create the following web.config
file in your Web root:
<configuration> <system.web> <httpHandlers> <add
verb="GET"
path="*.mspress" type="Mauvais.Samples.MSPress.ComplexHandler,
ComplexHandler"/>
</httpHandlers> </system.web
>
The path
attribute specifies the extensions that it will handle. Note
that the type
is a two-part value: the first part identifies the namespace
and class that will implement the handler, and the second part
provides the assembly name. You will need to be sure that the
assembly itself is located in the application's search path.
Verb refers to
the HTTP verbs that it will handle. If you want to process all
verbs, you would use an asterisk; in this example, HTTP verbs
are limited to GET requests.
Finally, you need to add the application extension in IIS.
To do this, fire up Internet Information
Services Manager and navigate to your default Web site,
right-click, and select Properties. Select
the Home
Directory tab, and click on Configuration as
shown in Figure 1.
Figure 1: You must modify the Default
Web Site Properties to add a custom handler.
In the Application Configuration window, click the Add button to bring
up the Add/Edit Application Extension Mapping dialog shown in
Figure 2. In this dialog box, click the Browse button and
navigate to aspnet_isapi.dll, which in the case of the .NET
Framework version 1.0 is located by default in
c:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\aspnet_isapi.dll.
In the Extension text box,
enter .mspress. Be sure to clear the Check That File Exists
checkbox because this sample does not rely on a physical file.
If you want, you can either limit the verbs or accept the
default setting of All Verbs. For this example, I chose to
limit it to GET to be a little more security
conscious.
Figure 2: Use this dialog box to add
application extension mapping.
There you have it. Now that everything is configured, you
should be able to browse to http://localhost/Scott.mspress (or
use whatever name you want) and your custom HTTP hander will
respond with: Hello, Scott!
For More Information
This month I started off with an architectural overview of
HTTP handlers and discussed their benefits compared with ISAPI
filters. Next I walked you through creating a simple HTTP
handler. Finally, I discussed the differences between simple
and custom handlers and showed you how to build and deploy a
custom handler.
This article only scratches the surface of what you can do
with HTTP handlers. To learn more about them, you will want to
pick up a copy of Developing
Microsoft ASP.NET Server Controls and Components by Nikhil
Kothari and Vandana Datye.
For additional code samples, see the HTTP
Handlers section of the .NET Framework Developer's
Guide.
If you are new to ASP.NET, you'll want to pick up a copy of
Microsoft
ASP.NET Step by Step by G. Andrew Duthie. This book
provides a great introduction to the technology itself and to
the best practices of developing Web applications.
Also check out the following resources for information
related to developing for the .NET Framework:
For a more broad overview of all the .NET technologies, you
should look at David S. Platt's Introducing
Microsoft .NET. It has some great information on COM
Interop, Windows Forms, and .NET memory management.
|