Skip navigation

XML-HTTP Callbacks: The Better Way

Plus: ASP.NET 2.0’s Image-generation Service, and Must HTTP Modules Be Thread-safe?

Q: I love the client callback manager built into ASP.NET 2.0. I'd like to be able to do lightweight XML-HTTP callbacks in ASP.NET 1.x applications, too. Is it doable with a reasonable amount of code?

A: You bet. ASP.NET 2.0's client callback manager uses the XML-HTTP support that Internet Explorer 5.0 and higher borrow from MSXML.dll. In an ASP.NET 1.x app, you can leverage that support yourself to perform lightweight callbacks to the server.

To understand why lightweight callbacks are so attractive, consider the Web page shown in Figure 1. It presents to the user two text boxes for entering a city name and a ZIP Code. Enter a ZIP Code that begins with 379 or 980 and click the Autofill button and "Knoxville" or "Redmond" will appear in the City field (see Figure 2). The Autofill button posts back to the server, where a server-side event handler performs a lookup and writes the corresponding city name into the City box. In a real app, the event handler would probably query a database or Web service to convert the ZIP Code into a city name, but you get the picture.


  
    
City
Zip

Figure 2: Clicking the Autofill button autofills the City field.

Autofill1.aspx relies on conventional postbacks to execute code on the server. Unfortunately, postbacks are expensive. Not only does the browser submit the entire form, but the page flashes because it's rerendered using the new HTML generated by the server. If you find yourself thinking there has to be a better way, you're right.

The "better way" is XML-HTTP. Rather than submit the entire form back to the server and rerender the page, Internet Explorer can perform lightweight callbacks to the server by transmitting XML-HTTP requests. The trick is to instantiate an XMLHTTP ActiveX object on the client, and use that object's Open and Send methods to fire off an XML-HTTP request.

Autofill2.aspx demonstrates how (see Figure 3). It wires the Autofill button to a client-side click handler that calls a JavaScript function named __doCallback, which in turn, sends an XML-HTTP request to the server. The request includes an __COMMAND parameter identifying the request as a callback and an __ZIP parameter containing the ZIP Code in the Zip field. Upon receiving these values, the page's Page_Load method returns a city name and short-circuits the request by calling Response.End. When the XML-HTTP call returns, the same client-side script that launched the call to begin with extracts the return value from the XMLHTTP object's responseText property and displays it in the City field.


  
    
  
  
    
City
Zip

Functionally, Autofill2.aspx is identical to Autofill1.aspx. Performance-wise, it's much more efficient. It minimizes the volume of data passed in the request and the ensuing response, and it prevents the browser from rerendering the page. It's also more efficient on the server, because only a fraction of ASP.NET's normal request-processing regimen is executed when the XML-HTTP request arrives.

The XML-HTTP requests launched by Autofill2.aspx differ from the ones transmitted by ASP.NET 2.0's client callback manager in one significant respect: Autofill2.aspx performs synchronous calls, and ASP.NET 2.0 calls back to the server asynchronously. You can modify Autofill2.aspx to perform asynchronous calls by changing Open's third parameter from False to True. If you do that, you'll also need to use the XMLHTTP object's onreadystatechange property to designate a client-side function that's called when the asynchronous call completes.

XML-HTTP callbacks are a fine way to improve performance and enhance the user experience. Consider using them any time you need to get back to the server to perform a lookup or some other chore, but don't need to submit the entire form or rerender the page. Also note that XML-HTTP is an option regardless of whether the platform is ASP.NET 1.x or 2.0.

Q: I'm experimenting with ASP.NET 2.0's image-generation service as a means for graphing data returned by a database query. My code is in an ASIX file, but I can't figure out how to specify the width and height of the image generated from that file. The default width and height are not sufficient. Can you help?

A: Sizing images generated by ASIX files isn't difficult - once you know how. The secret is to override the ImageGenerator base class' virtual DefaultWidth and DefaultHeight properties, and return the desired width and height in pixels. The example in Figure 4 uses this technique to create a 240x180 image. Feel free to use it as a template for ASIX files of your own.

<%@ Image Language="C#" Class="MyImageGenerator" %>
using System;
using System.Drawing;
using System.Web.UI.Imaging;
public class MyImageGenerator : ImageGenerator
{
   protected override int DefaultWidth
  {
     get { return 240; }
  }
   protected override int DefaultHeight
  {
     get { return 180; }
  }
   protected override void RenderImage(Graphics g)
  {
    // TODO: Generate the image
  }
}

Q: Do custom HTTP modules need to be thread-safe, reentrant, or both? Is it possible for an event handler in an HTTP module to be called simultaneously on two or more threads?

A: In general, HTTP modules don't have to be either thread-safe or reentrant. ASP.NET dispatches simultaneous requests on different threads. Each thread is associated with a unique HttpApplication object, and each HttpApplication object has its own set of module instances. Here's the bottom line: If two requests execute concurrently, two instances of each HTTP module are created, and each executes independently of the other.

The one exception is if a module that you're writing accesses data that is shared by all instances of that HTTP module. If, for example, the module contains static fields or other shared type members, then those type members should be accessed in a thread-safe manner. That typically means using System.Threading.Monitor or a similar class to serialize access to the shared resource.

The sample code in this article is available for download.

Jeff Prosise is the author of several books, including Programming Microsoft .NET (Microsoft Press, 2002). He's also a cofounder of Wintellect (http://www.wintellect.com), a software consulting and education firm that specializes in .NET. Have a question for this column? Submit queries to [email protected].

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish