Freigeben über


I've upgraded and now my application doesn't work anymore

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

Comments

  • Anonymous
    January 23, 2007
    Hmmm....seems like strange semantics for Flush() to me. I'd have thought, based on most other stream/network/disk APIs in existence that for a buffered connection Write() buffers and queues data, while Flush() blocks until it's been sent/written to the network/disk. Surely that's the point of Flush(), to block, isn't it? Hang on - what does even Flush() do in this scenario? What is Write() doing if not putting data onto a send-buffer? By making flush non-blocking, haven't you just turned it into a no-op?

  • Anonymous
    January 23, 2007
    The comment has been removed

  • Anonymous
    January 23, 2007
    Response.Clear()?!? Are you guys going to add funputc() to your C libraries anytime soon for symmetry with this? Or is having API consistency something you're actively avoiding? boggles

  • Anonymous
    July 18, 2007
    The comment has been removed

  • Anonymous
    October 28, 2007
    Thank you this helped me!

  • Anonymous
    November 01, 2007
    I removed response.flush and response.close, and replaced them with response.end.  It causes an exception: A first chance exception of type  'System.Threading.ThreadAbortException' occurred in mscorlib.dll

  • Anonymous
    November 01, 2007
    Hi Arlene, Don't worry. That's expected. All calls to Response.End will cause a first chance ThreadAbortException. This includes calls to Response.Redirect, which also calls Response.End. / Johan

  • Anonymous
    April 10, 2008
    Problem: When using Visual Studio 2005 to debug a web application under IIS7 you will find that after

  • Anonymous
    April 24, 2008
    This Seems to work Perfect for Your Scenario, but what if we do not want to call this.Page.Response.End() because there is more data that needs to be displayed but it will take a while to load. how can we send info to the client and then continue loading the rest of the page on IIS6?

  • Anonymous
    April 24, 2008
    Hi Oscar, Response.Flush will send what's currently in the buffer and then continue executing as normal. / Johan

  • Anonymous
    November 18, 2008
    The comment has been removed