October 25, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Asynchronous Http Handlers

  • July 10, 2002
  • By Jason Clark
  • Send Email »
  • More Articles »

Asynchronous Http Handlers

Asynchronous Http handlers work similarly to regular http handlers, except that they are capable of serving many client requests with very few actual threads. In fact, depending on how religiously the handler-code uses asynchronous methods in its implementation, it is possible to peg the CPU(s) in a system using only a handful of threads while serving many times as many clients. This approach has excellent scale-up possibilities.

To implement an asynchronous Http handler, your class must derive from the IHttpAsyncHandler interface rather than the IHttpHandler interface as seen in Listing 1. But the interface used is not the only difference between synchronous and asynchronous Http handlers. The program flow is also a bit more difficult to design.

The tough part of implementing an asynchronous Http handler is working with the Asynchronous Programming Model. All IO requests that you make in the process of creating the http response should be done asynchronously by using Begin*() and End*() methods, rather than their synchronous equivalents. For example, if your handler needs to read bytes from a file it should call BeginRead()/EndRead() on the Stream object rather than simply calling the synchronous Read(). You should call BeginRead() such that it calls your code back when the read has completed; meanwhile, your thread can be returned to the pool so that it is not wasted on an idle block.

In addition to using asynchronous Begin*() and End*() methods exclusively for all of your "blocking" IO calls, your asynchronous handler must also implement asynchronous BeginProcessRequest() and EndProcessRequest() methods that are called asynchronously by ASP.Net itself. The BeginProcessRequest() and EndProcessRequest() are the IHttpAsyncHandler interface's methods that allow ASP.Net to do asynchronously what it would have done synchronously using IHttpHandler's ProcessRequest() method.

Here is a summary of the things that you will have to think about when creating an asynchronous Http handler.

  1. You should do all of your IO using asynchronous Begin*() and End*() methods.
  2. You must implement Begin*() and End*() methods that allow ASP.Net to call you asynchronously.
  3. You must create a type that implements IAsyncResult that you instantiate and return to ASP.Net from your Begin*() method. ASP.Net will pass the object back to your End*() method. You should use this object to keep track of client-request state (such as the context object) as the work is divided amongst multiple calls.

The code shown in Listing 2 is a very simple asynchronous http handler (which you can deploy in the same manner described for the code in Listing 1).

<%@ WebHandler Language="C#" Class="AsyncHttpHandler"%>

using System;
using System.Web;
using System.Threading;

public class AsyncHttpHandler : IHttpAsyncHandler {
  public IAsyncResult BeginProcessRequest(
    HttpContext context, AsyncCallback cb, Object extraData){
    // Create an async object to return to caller
    Async async = new Async(cb, extraData);
    // store a little context for us to use later as well
    async.context = context;

    // Normally real work would be done here... then, most likely
    // as the result of an async callback, you eventually
    // "complete" the async operation so that the caller knows to
    // call the EndProcessRequest() method
    async.SetCompleted();

    // return IAsyncResult object to caller
    return async;
  }
  
  // Finish up
  public void EndProcessRequest(IAsyncResult result){
    // Finish things
    Async async = result as Async;
    async.context.Response.Write(
      "<H1>This is an <i>Asynchronous</i> response!!</H1>");
  }

  // This method is never called by ASP.Net in the async case
  public void ProcessRequest(HttpContext context) {
    throw new InvalidOperationException(
              "ASP.Net should never use this method");
  }

  // This means that the same AsyncHttpHandler object is used
  // for all requests returning false hear makes ASP.Net create 
  //  object per request.
  public bool IsReusable {
    get { return true; }
  }
}

// This object is necessary for the caller to help your code keep
// track of state between begin and end calls
class Async:IAsyncResult{
  internal Async(AsyncCallback cb, Object extraData){
    this.cb = cb;
    asyncState = extraData;
    isCompleted = false;
  }

  private AsyncCallback cb = null;
  private Object asyncState;
  public object AsyncState {
    get {
      return asyncState;
    }
  }

  public bool CompletedSynchronously {
    get {
      return false;
    }
  }

  // If this object was not being used solely with ASP.Net this
  // method would need an implementation. ASP.Net never uses the
  // event, so it is not implemented here.
  public WaitHandle AsyncWaitHandle {
    get {
      throw new InvalidOperationException(
                "ASP.Net should never use this property");
    }
  }

  private Boolean isCompleted;
  public bool IsCompleted {
    get {
      return isCompleted;
    }
  }

  internal void SetCompleted(){ 
    isCompleted = true;
    if(cb != null){
       cb(this);
    }
  }

  // state internal fields
  internal HttpContext context=null;
}

Listing 2—Async.ashx, an asynchronous Http handler.

There is more to say about asynchronous server code, and if this article generates interest, perhaps I will publish a second part on this site in the future. Unfortunately, though, this article has already reached more than double its expected size for the Web site and I frankly hope they have space for this much! Fortunately, this coverage should get you well on your way to writing scalable server-side code using asynchronous Http handlers.

In future versions of the .NET Framework, look for more innovations in the asynchronous programming model. For example, eventually there will be an asynchronous Page object that provides a way to implement Web forms and other more structured Web applications asynchronously.

This is cool stuff. Have fun!

About the Author

Jason Clark has been banging code since he fell in love with computers way back in sixth grade. Since the early nineties, Jason professional life has been devoted to Windows development. His most recent full-time employment was with Microsoft, where he wrote security protocols for the Windows operating systems.

Jason now does software consulting and writes about a variety of topics ranging from developing secure software to writing software that runs on Microsoft's new .NET platform. Jason coauthored Programming Server-Side Applications for Microsoft Windows 2000, and he writes articles for Dr. Dobbs Journal, MSDN Magazine (formerly MSJ), Windows Developers Journal, and other leading developer magazines. Jason's commercial software credits include work he has performed for Microsoft, IBM, Sony, HP, and other companies, and involve everything from writing printer drivers to helping develop the Windows 2000 and "Whistler" operating systems.

# # #





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel