Scenario:

A quite common scenario when working in the support industry is a call along theese lines:

"My application worked just fine, but now that I've upgraded to IE7, IIS6, Vista, etc. it doesn't work any more. This has got to be a bug! This new version of the software obviously isn't any good, so when are you going to fix it?"


Is it a bug?

Well, possibly. But most likely the bug doesn't lie within IE, IIS or the operating system. Instead you should look at your code to make sure you did everything following the recommended guidelines. Chances are that you didn't do things the right way originally, and for some reasons the previous version of the software was more forgiving.

Example

A little while ago I had the following scenario on my hands:

A customer had just upgraded their webservers from Windows 2000 to Windows 2003. After the upgrade certain requests just "vanished" into thin air. The response never reached the clients. We managed to track down the problem to the following lines of code:

this.Page.Response.ClearContent();
this.Page.Response.Write(TextToWrite);
this.Page.Response.Flush();
this.Page.Response.Close();

Okay, so you probably see what is strange here. Why are they calling Response.Flush() and Response.Close()?

If we remove theese two lines and replace them with Response.End() then everything works fine:

this.Page.Response.ClearContent();
this.Page.Response.Write(TextToWrite);
this.Page.Response.End();

Okay, so this is the proper way to do it. Response.End() will call actually call Response.Flush() and then gracefully end execution of the page, while Response.Close() will simply "cut the cord". But how come it worked in IIS5 and not IIS6? Does this mean that IIS6 is a bad product? - Not at all!

One of the things that changed with IIS6 is that it now processes responses asynchronously. This means that in IIS5 all execution will be paused until the page has been sent, while in IIS6 the response will be put in a send-buffer, allowing IIS to immediately continue execution. This is one of the reasons why IIS6 is both faster and more secure than IIS5. The thread executing the page does not have to take the connection speed of the client into consideration. It can execute the page and move on to the next. In IIS5 all execution on the thread would be stopped until the client had downloaded every last bit. This made the server more vulnerable to Denial of Service (DOS) -attacks, and something as trivial as a bunch of clients with poor modem connections could impair the performance of the server.

In brief, here’s what happened with the old code:

IIS5:

  • Response.Flush sends data to client
  • Thread waits until data has been sent
  • Response.Close closes client connection

IIS6:

  • Response.Flush puts the data in a send buffer and immediately moves to the next line of code
  • Response.Close closes the client connection before the data has been sent

Here’s what happens with the new code:

IIS5:

  • Response.End is called
    • The data is sent to the client
    • IIS gracefully ends all further execution of the page

IIS6:

  • Response.End is called
    • The data is transferred to the send buffer
    • IIS gracefully ends all further execution of the page

Summary:

The old code was incorrect, but worked anyway due to the synchronous design of IIS5. As IIS6 switched to an asynchronous response model this stopped working. I can sympathize with anyone that feels that this is a bug/mistake, but in reality it isn't. In fact it is a very concious choice made to further improve performance and reliability.

/ Johan