From the July 2001 issue of MSDN Magazine.

MSDN Magazine

ASP.NET Connection Model and Writing Custom HTTP Handler/Response Objects
George Shepherd
Download the code for this article:ASP0107.exe (38KB)
W

elcome to the first installment of The ASP Column. Software development has come a long way from the days when I first started reading the pages of Microsoft Systems Journal in the late 1980s. Back then I was concerned with MS-DOS® as an operating system, writing Terminate-and-Stay-Resident programs, and deciding if I should worry about this thing called OS/2. Back then the Internet was something very few companies had heard of and the World Wide Web was a pipe dream.
      Everything's different now. The Internet is today's programming platform. ASP has played a huge role in getting Web sites up and running. ASP.NET continues the trend. This column covers all ASP, all the time. If it has to do with ASP and ASP.NET, I'll cover it here. This includes such items as the ASP and ASP.NET architectures, writing components for ASP and ASP.NET, server-based UI, and integrating with back end systems.
      This month I'll start by looking at ASP.NET's connection model and how to write custom HTTP handler/response objects for ASP.NET. When it comes right down to it, the day-to-day life of a Web server really just involves receiving client requests and responding to them appropriately using HTTP. Understanding this fact and how ASP evolved into ASP.NET makes understanding ASP.NET's connection model simple.

Classic ASP versus ASP.NET

      The earliest non-static Web sites were built using the Common Gateway Interface (CGI). CGI processed requests directly, issuing responses by firing up a custom process to handle incoming HTTP requests. The next step in improving Web site performance was to process HTTP requests through DLLs, which are much less expensive than loading new processes. On the Windows platform, these are known as ISAPI DLLs which are customized to spit out HTML specific to the task.
      ASP was introduced because the process of writing ISAPI DLLs was burdensome. Think of classic ASP as one big ISAPI DLL that Microsoft has already written for you. Classic ASP accepts HTTP requests and posts back responses. You control the content coming from ASP using ASP code. ASP parses files with .ASP extensions and does its best to emit the right kind of HTML. Classic ASP pages include both raw HTML and script blocks. Accessing the HTTP requests and responses at runtime is possible because the requests and responses are wrapped in well-established objects you can access from the script blocks.
      Classic ASP goes a long way towards simplifying Web programming. It's often much easier to write some HTML and mingle it with some script than it is to write a new DLL from scratch. But classic ASP is not without its issues. First, ASP code is often without structure. It's very much like the early days of BASIC programming where you could get something done quickly, but the resulting code was often too difficult to follow.
      ASP.NET is the evolution of ASP. For example, you still have the same intrinsic objects in ASP.NET and you can add scripting wherever you want on the page. In fact, most ASP pages can be run as ASP.NET pages with no problem.
      But ASP.NET brings a lot of new stuff to the table. First, ASP.NET supports every .NET-compliant language. No longer are you confined to using JScript® or VBScript on your Web pages. ASP.NET lets you write the executable parts of your pages in C# or Visual Basic (or COBOL). Second, ASP.NET is compiled into assemblies just like the other languages in .NET. This provides both enhanced performance and security benefits.

De-emphasizing ISAPI

      At the heart of ASP.NET is the ability to service HTTP requests and responses. In this vein, ASP.NET de-emphasizes the ISAPI architecture. ASP.NET prefers the .NET common language runtime (CLR) to the ISAPI/ASP architecture. While classic ASP uses a single request/response handler, ASP.NET works by dispatching HTTP requests to user-defined handler objects. That is, those objects implementing a .NET interface named IHttpHandler. You can bind URI paths to classes for handling specific requests. For example, if someone submits a query for some information, you can map that URI to a specific class for handling that query. Certain incoming URIs that aren't mapped to a specific handler class are swallowed by ASP.NET's default handler and will target the URI as a file name, loading the file specified within the URI. Most of the time, the file specified in the URI is a basic .ASPX file.

Responding to Requests Using ASP.NET

      The core of every ASP.NET page is the System.Web.UI.Page class. Most ASP.NET pages work by extending this class. System.Web.UI.Page implements the core ASP.NET interface named IHttpHandler, enabling the Page class to receive HTTP requests and deliver responses. I'll look at that interface in more detail shortly, as I'll need to implement it to write a custom handler. The Page class includes a Response object, really just a wrapper that's useful for spitting out HTML to the browser connected to the other end. Figure 1 shows an ASP.NET file that spits a little bit of HTML out to the browser advertising the .NET type of the page. Figure 2 shows the output to a browser.

Figure 2 Browser Output
Figure 2Browser Output

      The <% %> block markers specify a block of code and the language to use to execute the block. Notice that the structured C# code fits in with the rest of the page. Also notice that the base class is the System.Web.UI.Page. The Page class includes a Response object suitable for spewing the text out to the browser. The C# code that executes simply asks the page for its .NET type and sends that string back to the browser.
      In classic ASP, the Response object was an intrinsic object. In ASP.NET, the Response object is moved into the Page class, making it a bit easier to manage. You don't need to push all your markup language through the Response object. ASP.NET lets you include markup text as part of the page itself (just as in ASP). However, the ASP.NET model makes it easier to customize your output through the Response class, as shown earlier.

Handling Requests

      All you need to get a rudimentary Web site up and running is an HTML or ASP file in the root directory of your Web site. For example, you can type: https://www.plural.com in the browser's address bar. If the server is running Windows® and Microsoft Internet Information Services (IIS) 5.0 and you don't specify a file name, IIS first looks for a file named default.htm (depending on how the server is set up) and sends the HTML to the browser. In this way, default.htm is the jumping-off point for many Web sites. If that page is missing from the Web site, the browser reports an error.
      The URI can also include the name of a subdirectory on the Web site or even a file name. If a file name is specified like the following URL, IIS loads the specified file, parses it, and emits some markup text to the browser.

https://www.plural.com/index.asp
      So without even thinking about it, the ASP code you write is automatically handling HTTP requests. But how do you map requests to other handlers to handle specific requests? ASP.NET makes it easy to set up separate handlers.

ASP.NET Connection Object Model

      HTTP is basically a connectionless protocol. Unlike a connection-intensive protocol like DCOM, clients connect to the server only for the duration of an HTTP request. That means ASP.NET needs to have some way of managing the connections within an application. The class used for this is System.Web.Http.Context.
      ASP.NET generates one HttpContext object for each request serviced and passes the context object to HTTP handlers (of which System.Web.UI.Page is one). You can always get to the current HttpContext object because it's exposed as a static property: HttpContext.Current. You can use the HttpContext object to get information about the request and its relationship to your application. In Figure 3, HttpContext is used for getting information about the HTTP request. In addition, HttpContext manages the session state—you can get to the session state information through the HttpContext object via the Session property.
      The code in Figure 3 gets current connection state and queries it for the current HTTP request and the URL used to get to the page. So if you can get an HttpContext, you're able to easily emit HTML to the client attached to your server. ASP.NET makes it possible to assign separate handlers for separate classes by implementing the IHttpHandler interface. Let's see how.

Writing Custom Handlers

      Setting up custom handlers for each request involves simply setting up a class to implement IHttpHandler and mapping the request to the handler using the config.web file associated with the Web site. Here's the IHttpHandler interface in C#:
interface IHttpHandler {
   bool IsReusable();
   void ProcessRequest(HttpContext context);
};
      IHttpHandler has two functions: IsReusable and ProcessRequest. ASP.NET calls IsReusable to find out if the handler can be recycled. ProcessRequest is where you put your response code. Figure 4 shows IHttpHandler implemented in C#.
      There's not much to this class. It simply takes the request/response context provided by ASP.NET for the particular request and says "Hello World in C#!" You can put in any markup code you want. You can also access the other properties of the connection context to do more specialized things, which I'll look at in later columns.
      Figure 5 shows the same request handler written in Visual Basic .NET. The Visual Basic® handler works the same way. In fact, when you look at the intermediate language code emitted by the compiler, it's virtually identical. Next I'll describe how to associate the handler with a specific request.

Mapping Requests to Handlers

      Each Web site can have a config.web file associated with it. The <httphandlers> block within the <configuration> block associates the incoming requests to an assembly implementing the handler. Figure 6 shows how to associate handlers to incoming requests.
      This config.web file associates incoming requests with the handlers shown in Figure 4 and Figure 5. For example, if you type the URL https://localserver/vbhandler.aspx, ASP.NET will route the request to the VBHandler class and you'll see "This is Visual Basic" appear in your browser.

Conclusion

      I've only scratched the surface of custom handlers here. In future columns, I'll look at routing requests to do more useful things. In addition, I'll look at more advanced topics like HTTP handler factories.
      Overall, the new .NET platform has lots to offer the software developer, including an ecumenical type system, better type information, and an efficient compilation model which truly tightens up the boundaries between components. Riding herd over all this great stuff is ASP.NET, which I believe will be the killer app for .NET. Until now, there hasn't really been a way to use the Internet as a software platform. However, the technology is in place to make that happen, and ASP.NET makes it much easier to manage Web programming. ASP.NET keeps all the important features of ASP (in-proc performance, a well-established syntax, the ability to add executable blocks to your Web page), and improves upon it by providing a more granular HTTP request handling model, providing a compilation model for Web pages, organizing the parts of a Web page into classes, and making those classes available through the CLR type system. ASP.NET will undoubtedly be the tool of choice for most Web developers over the next five to ten years.

Send questions and comments for George to asp-net@microsoft.com.
Want to help us rename The ASP Column? Try as we might, we haven't come up with the perfect moniker. So we figured we'd hand the job over to our readers. Please send your suggestions to asp-net@microsoft.com with "column name" in the subject line by August 1, 2001. If your suggestion is selected, we'll send you an MSDN Magazine mug and T-shirt. But most importantly, you'll have the satisfaction of naming this column!
George Shepherd is an associate technology director at Plural where he helps companies use Microsoft technologies effectively. In addition, George delivers seminars with DevelopMentor and is the coauthor of an upcoming book Applied .NET from Addison-Wesley.