AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=1684&pId=-1
Roll Your Own HttpHandler
page
by Brendan Enrick
Feedback
Average Rating: 
Views (Total / Last 10 Days): 34665/ 49

Introduction

One of the more interesting pieces of ASP.NET is the concept of HttpHandlers. Sadly, this article does not delve much into what handlers are or for what they are used. Instead, this article just gives a quick introduction for you to be able to write your own HttpHandler. The text following explains how to create a simple HttpHandler, and a few of the design decisions you will have to make when creating your own. You can download the sample project for this article here or at the bottom of the article.

There are plenty of ways in which one can benefit from the use of HttpHandlers. They are very versatile. They can be applied to a lot of different tasks. Keep in mind there are also HttpModules which are also extremely useful tools, but they are a bit different from HttpHandlers. I will not be delving into that topic in this article. Please read elsewhere to learn more about the differences between HttpHandlers and HttpModules.

I know plenty of people who have configured IIS to send all requests for gifs, pngs, jpgs, etc. to ASP.NET HttpHandlers so that site owners can clamp down on hotlinking, leeching, or whatever you want to call it. It is where someone else links to your sites content. It uses your bandwidth and you do not even get the traffic, and usually it does not mention where the content came from.

Other people will configure IIS to handle zip files so that an HttpHandler can step in and execute code every time someone wants to download a file from a site. This is much easier than some of the scripted downloads, and certainly gives great server-side control over the download - counting the number of downloads and storing in a database or whatever you want to do.

One other use of HttpHandlers, which I plan to write about soon, is to use them to watermark your images. If you have configured an HttpHandler to prevent people from leeching your images you might also use a handler to watermark your images with a copyright. This makes it less likely that people will simply save your images and display them on their own pages. Plenty of people and companies are quite concerned about this. Keep in mind that if you publish something on the internet it can never be completely safe, but you can at least discourage people.

Setting up the Solution

Start by getting yourself a solution to work with. You will want to have 2 projects in the solution. One needs to be some form of a web application, either your production application or just one with which to test. You will also want to have a Library. This DLL built by the library will be the HttpHandler. The website will be configured to send certain requests to be handled by the handler in that assembly.

Once you have created your solution you should have a solution explorer that looks a little bit like mine. As a note, keep in mind that I am using a web application project and not a web site. You can use a web site if you want. I prefer web application projects, but web sites work perfectly well also.

Figure 1: Solution Explorer Initial Setup

It is important to make sure that we tie these two applications together. We will use a project reference here so that we can have the assembly of our handler build and be added into the web application so it can use it. To do this just click on the reference folder in your project and select add a reference. This will probably take some time to load the first time you run it.

Figure 2: Adding Project Reference

Before you can actually turn the class library into a handler, there is one assembly you will need to include for it. This assembly is the System.Web assembly. This is the one which contains the information about dealing with the web. Handlers are obviously web related, so we will add that assembly to our class library project. Do this just like before, right clicking on the references folder and choosing to add a reference. This will probably be faster than the first time, so once it loads you can just find the correct assembly in the list.

Figure 3: Adding a System.Web Reference

Once you have added the System.Web reference you will be able to use the IHttpHandler interface, which is really all that is needed in order to create a handler. Any class that implements that interface is able to be a handler. The interface only has two methods which must be implemented. There are the IsReusable property and the ProcessRequest method.

Implementing the IHttpHandler Interface

Implementing interfaces is quite easy. If you are completely new to interfaces and do not understand them at all. I recommend you take a look at an article I wrote which describes the basics of how to use interfaces.

The IHttpHandler interface is a small one, containing only two methods. One is a property which is likely to have a set value. The other is the method which process the request. It is aptly named ProcessRequest. It takes as a parameter an HttpContext variable which is basically a one-stop shop object for dealing with requests. It gives you access to necessary objects and information.

The IReusable property does exactly as its name states. It determines for this class whether an instance of the class can be reused. If this value is set to true then the same class will continue to be used for subsequent requests. This means you could keep a count inside the class of the number of requests. You could have class-level variables handling the requests. This also means that the state of the class will change from request to request, which can cause problems if not handled correctly. The easiest answer is just to say that a class is not reusable unless you actually need it to be.

The last and most important function involved in HttpHandlers is the ProcessRequest method. As I stated earlier, it has one parameter of type HttpContext. This parameter gives access to the Response and Request objects which are two of the most commonly used objects in ASP.NET, and as such should be reasonably well understood. Request gives all of the information about the request which has been made, and Response is all of the information about the response which will be sent back to the browser. The context will also give access to the Sever and Application objects and plenty more.

In this example I explain how all of this works and just use a simple example to illustrate what I mean. I leave creating a more advanced solution up to future articles I write, as well as an exercise for the reader. I will name the handler SimpleHandler and set it to implement IHttpHandler. This is what the class looks like at the beginning.

Listing 1: SimpleHandler Empty

namespace RollYourOwnHttpHandler
{
    public class SimpleHandler : IHttpHandler
    {
        public SimpleHandler()
        {
        }
    }
}

Right now we have a compiler error, so we need to implement the interface we are saying we will implement. If we right click on the interface name and choose the "Implement Interface" option, it will add this code for us.

Listing 2: Interface Implementation

#region IHttpHandler Members
 
public bool IsReusable
{
    get { throw new NotImplementedException(); }
}
 
public void ProcessRequest(HttpContext context)
{
    throw new NotImplementedException();
}
 
#endregion

This code is just enough to get our class compiling. It will not work yet. First we need to remove those NotImplementedExceptions it is throwing. We can start with the IReusable property since it is by far the easier of the two.

In our example we will not be storing any class level information, so the state of our handler instance will never change. This means we should be relatively safe using the same instance of this class to handle multiple requests. This will make things nice for our solution as long as we maintain this lack of state. So for now we can just set the IsReusable property to true. Just so it is clear, I am changing that property to the following code.

Listing 3: IsReusable Property

public bool IsReusable
{
  get { return true; }
}

This leaves us with only one section of code left to write: the ProcessRequest method. In this section you can make your code as simple or as complicated as you like. Perhaps you will just be keeping a count of something. Maybe you will be making a record in a database which is logging this transaction. Or you could be doing some complex calculations about something. Either way this is the core of the handler. This is the handling code. Do in here whatever you wish. Keep in mind that if you are doing anything which affects the state of this instance of this class you will want to pay careful attention to that state as well as the IsReusable property.

Since this is just an example showing how to perform this action, it will just be a simple hello world program. To do this we can use the context object to give us access to the Response object. We can then just write some html directly into the Response. This is certainly not how you would want to use any complicated handlers, but it works well enough for our example.

Listing 4: ProcessRequest Method

public void ProcessRequest(HttpContext context)
{
    context.Response.Write("<html><head><title>Hi there!</title></head>" + 
        "<body>Hello world!</body></html>");
}

Notice that there are plenty of uses for HttpHandler. You could do many different tasks with them. This simple method is just to illustrate how to implement this method. You can certainly write plenty of other code here.

Configuring the Web.config

Before we can see this handler in action, we need to wire up the web configuration file. This file can be found in the root of your web application project or web site. In this file is an HttpHandler section. It contains the information related to these handlers. We need to define ours in here. The important information is the fully-qualified name of our HttpHandler's type. This means the full namespace followed by the class name. In our case this is RollYourOwnHttpHandler.SimpleHandler. We also need to include the name of the assembly where the handler resides. I named it RollYourOwnHttpHandler, which happens to also be the namespace.

The verb we define as * means that we want this handler to take care of all of the different actions for these. This means it will handle everything including gets and posts. We define a path which we want to handle. The * is a wildcard so we want to handle any request whose path ends in .hello; so we have effectively created a fake file extension here for this handler. The type attribute uses the other information we discussed, the fully-qualified name of our HttpHandler type followed by a comma and then the name of the assembly.

Listing 5: Configuration

<configuration>
    <!--Other config information here-->
    <system.web>
      <!--Other config information here-->
      <httpModules>
        <add verb="*" path="*.hello" 
            type="RollYourOwnHttpHandler.SimpleHandler, RollYourOwnHttpHandler"/>
      </httpModules>
      <!--Other config information here-->
    </system.web>
    <!--Other config information here-->
</configuration>

If we use a path of "*.aspx" then our handler will intercept asp.net's normal traffic. This gives us some neat functionality. We just need to make sure that at the end of our ProcessRequest method we pass control back over to the standard ASP.NET handler or we will have eliminated our normal ASP.NET traffic.

Configuring IIS Application Extensions (optional)

If you are using a path which is not normally mapped to ASP.NET, you will need to let IIS know that it needs to send the traffic to be handled by ASP.NET. This does not need to be done for the development server built into Visual Studio. So if you are running in Visual Studio, this task is not necessary until you are going to deploy this to a server running IIS.

Launch IIS and right click on the web site you are using. Select Properties. In this window navigate to the tab labeled Home Directory. Click on the Configuration button. This will open up the Application Configuration window. We need to add another application extension, so click on the Add button. The Executable should be the file path of aspnet_isapi.dll, which can be found in your .NET Framework directory. This will vary based on your operating system as well as the version of the .NET framework you are using. The Extension should be the extension you want to map; in our case it is the .hello extension.

The HttpHandler

Now we have a handler which should be working correctly. To test this out we should run our web application project and then navigate to anything followed by .hello, and then our handler should take over execution and handle the request.

Here is what it looks like when our example SimpleHandler is used to handle a request.

Figure 4: Viewing the Handler

 

A fairly simple way to handle this, but it works quite well.

The final code in this example can be downloaded from the following link. I will also include the few lines of the SimpleHandler class here.

Listing 6: Final SimpleHandler

using System.Web;
 
namespace RollYourOwnHttpHandler
{
    public class SimpleHandler : IHttpHandler
    {
        public SimpleHandler()
        {
        }
 
        #region IHttpHandler Members
 
        public bool IsReusable
        {
            get { return true; }
        }
 
        public void ProcessRequest(HttpContext context)
        {
            context.Response.Write("<html><head><title>Hi there!</title></head>" + 
                "<body>Hello world!</body></html>");
        }
 
        #endregion
    }
}
Download
Conclusion

The basics of working with the IHttpHandler interface are pretty easy. There is not much to the interface, but it does allow you to easily create HttpHandlers. Make sure that you are careful with the IsReusable property. State bugs are often some of the hardest to track down. They can cause problems not easily discovered because they are so dependent on the state of the class at the time of the error that they are not easily reproduced. Enjoy handling requests in this manner. There are plenty of possibilities and a lot of power to be wielded using this technology. This should come in handy for you.

About the Author

Brendan Enrick



©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-19 4:26:50 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search