Image or ImageButton without ImageUrl Causes HTTP GET for Default Document

I recently worked an issue with a customer who was seeing an error in his application due to a null reference. The error was perplexing because the object that was null was populated on the logon page of the application, but the error was occurring after the user logged in. The object should certainly not have been null. Even more perplexing was the fact that the error could be reproduced readily on a Windows 2003 Server, but the exact same code would never reproduce the problem on the development machine running Windows XP.

In order to troubleshoot this problem, I had the customer get a Time Travel Trace, something we often call an iDNA dump. An iDNA dump is analyzed like any other memory dump, but unlike a traditional user-mode dump that contains the contents of memory at a particular moment in time, an iDNA dump contains a “recording” of user-mode memory over a period of time. It’s kind of like Tivo for the debugger, and in situations where a problem is easily reproduced in short time, it’s a great way to dig into problems.

Using the iDNA dump, I was able to determine that the customer’s code was successfully creating the object that was causing the NullReferenceException. I was also able to determine that the customer never explicitly set the object to null and the only place where we entered the constructor for the object was in the logon page just as the customer said. However, I also found that Page_Load for the logon page was hit in a seemingly random place long after the user logged in.

Next, I got a network trace of the application. In that trace, I saw a GET for “/” which causes the web server to serve up the default document. In my customer’s case, login.aspx was in the default document list, so this GET caused the code in login.aspx to run. In that code, the customer re-initialized an object and stored it in Session. One of the members of that object was the object causing the NullReferenceException, and because the code in login.aspx reset the variable in Session state, it overwrote the valid member object with a null. (Whew! If you had a hard time following all of that, just think how difficult it was to follow it all by setting breakpoints in Windbg!)

The GET for the default document that we were seeing was a big mystery. I could find nothing in the customer’s code that was doing that. I started trying to narrow down where that was coming from. Eventually, we found that it originated with an <input> element in the rendered page that looked like this:

<input type="image" src="" … />

When the browser encountered this element, it performed a GET for the default document. That explained why Page_Load was running for logon.aspx and it explained why we never saw this happen in the browser window. It also explained why the problem didn’t happen on Windows XP. On Windows XP, the customer was using the ASP.NET Development Server. The dev server doesn’t have any concept of a default document list, so when the GET occurred for the default document, it tried to serve default.aspx. Since there wasn’t a default.aspx in the application, the dev server simply served up a directory listing, and because that didn’t actually run any code, it had no impact on the application.

The XHTML that caused this problem was caused by an ASP.NET ImageButton control without an ImageUrl property. If you don’t specify an ImageUrl property for an ImageButton control (or any control that derives from Image), it will cause ASP.NET to render the XHTML you see above, and that will result in the errant GET. As you can tell from reading about my experience, it’s possible for this issue to cause bizarre bugs that are extremely difficult to track down. What’s worse is that these bugs can occur long after the GET that caused them.

We thought about correcting this now in version 2, but we were concerned that any change in the ASP.NET code would break existing applications. Therefore, we have this on the slate to look at for the next version of ASP.NET. In the meantime, always make sure that you specify an ImageUrl property when using a control that derives from Image!