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 removedAnonymous
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? bogglesAnonymous
July 18, 2007
The comment has been removedAnonymous
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.dllAnonymous
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. / JohanAnonymous
April 10, 2008
Problem: When using Visual Studio 2005 to debug a web application under IIS7 you will find that afterAnonymous
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. / JohanAnonymous
November 18, 2008
The comment has been removed