Udostępnij za pośrednictwem


Response.End, Response.Close, and How Customer Feedback Helps Us Improve MSDN Documentation

Last December someone used the feedback link on the HttpResponse.Close method in MSDN to send the following comment: "Where is any context on use and what is actually occurring?"

I maintain the HttpResponse class documentation, so this comment got routed to me. I did not assign it a high priority because it was not reporting an error and the HttpResponse.Close documentation was not getting a lot of traffic. But I put it in my to-do list, and eventually I found time to look into it further.

The comment was an understandable response to a minimal amount of documentation: all we had on HttpResponse.Close was a brief summary ("Closes the socket connection to a client.") and a one-line code example with an introduction that repeated the summary.

I did not know any more about the HttpResponse.Close method at this point than the customer who was frustrated by the brevity of our documentation. So I started with some Bing queries to see what information about this might already be available on the web. (Of course I work right here in the same building with the developers who created and maintain the HttpResponse class, and I could have gone straight to the horse's mouth. But it's generally better not to bother busy people with questions that you can find out quickly and easily in other ways.)

This one was not quick and easy. What I found was a lot of confusion. Many people were trying to use HttpResponse.Close but they didn't know what it was for, and they were having various problems with it. They were asking questions and not getting answers, or they were getting incomplete or inconsistent answers. Finally I found a forum post where a Microsoft person gave an answer that got me closer to what I was looking for. Here is how he answered a question about why using HttpResponse.Close caused some data sent to the client to be lost:

Response.Close sends a reset packet to the client and using it in anything other than error condition will lead to all sorts of problems - e.g., if you are talking to a client with enough latency, the reset packet can cause any other response data buffered on the server, client or somewhere in between to be dropped.

In this particular case, compression involves looking for common patterns within the response and some amount of response has to be buffered by the compression code to increase the chance of finding longer repeating patterns - this part that is buffered cannot be sent to the client once you do Response.Close().

In short, do not use Response.Close().

I asked the post's author (Anil Ruia) when you might actually want to use HttpResponse.Close. He wrote back that "... it should really only be used under error conditions to abort the response/connection." He cc'd another expert on the subject, Thomas Marquardt, who stated unequivocally:

It’s definitely in the “don’t use this API ever” category ... Response.End does in fact abort the current thread, so I wouldn’t use the term "abort" when talking about Response.Close, for fear of confusion. Response.Close calls HttpWorkerRequest.CloseConnection, which is described on MSDN as “Terminates the connection with the client.” The only thing I would add to the description of Response.Close on MSDN is that you shouldn’t call it, ever.

This left me in a bit of a quandary, because if I updated the documentation to say "don't use this ever," people would wonder why it's there in the first place. A follow-up email to Thomas elicited a more complete description of not only HttpResponse.Close but also HttpResponse.End:

The End method is also on my “never use” list. The best way to stop the request is to call HttpApplication.CompleteRequest. The End method is only there because we tried to be compatible with classic ASP when 1.0 was released. Classic ASP has a Response.End method that terminates processing of the ASP script. To mimic this behavior, ASP.NET’s End method tries to raise a ThreadAbortException. If this is successful, the calling thread will be aborted (very expensive, not good for performance) and the pipeline will jump ahead to the EndRequest event. The ThreadAbortException, if successful, of course means that the thread unwinds before it can call any more code, so calling End means you won’t be calling any code after that. If the End method is not able to raise a ThreadAbortException, it will instead flush the response bytes to the client, but it does this synchronously which is really bad for performance, and when the user code after End is done executing, the pipeline jumps ahead to the EndRequest notification. Writing bytes to the client is a very expensive operation, especially if the client is halfway around the world and using a 56k modem, so it is best to send the bytes asynchronously, which is what we do when the request ends the normal way. Flushing synchronously is really bad. So to summarize, you shouldn’t use End, but using CompleteRequest is perfectly fine. The documentation for End should state that CompleteRequest is a better way to skip ahead to the EndRequest notification and complete the request.

The Close method isn’t for debugging scenarios. Close terminates the connection with the client in an abrupt manner, and is not intended for normal HTTP request processing. This is the kind of thing you might do if your server was being attacked by a malicious HTTP client. It’s highly unlikely that you would have a good reason to call this method. You might consider calling CompleteRequest instead if you want to jump ahead to EndRequest and send a response to the client.

A review of the existing MSDN documentation for HttpResponse.End revealed that it too was in need of revision. So I updated the MSDN documentation for both HttpResponse.End and HttpResponse.Close to indicate briefly what they actually do and that HttpApplication.CompleteRequest is a better way to end a request. (Updates do not immediately go through to the public MSDN site; I would expect it to appear there in a month or so.)

I am providing this blog post as an example that shows how customer feedback comments, even simple requests for more information, can make a difference in improving MSDN documentation. It might take 6 months or more (as in this case) for you to see a change in MSDN due to our workload and other priorities, but every feedback comment gets personal attention and is taken seriously.

-- Tom Dykstra
ASP.NET User Education
This posting is provided "AS IS" with no warranties, and confers no rights.

Comments

  • Anonymous
    October 01, 2010
    Nice!! Now i understand Tesponse.End, thanks
  • Anonymous
    November 18, 2010
    This is extremely nice, now i know, Thanks for this explanation.But I have one question, consider a following scenario.I have a LinkButton in a DataGrid, of a summary page, whenever a user clicks on the LinkButton, the user is redirected to a detail page. In the ItemCommand event handler i have written following codevoid ItemCommand(...) {Response.Redirect("Detail.aspx", true);}If we see the page trace, The Page LifeCycle terminates at the itemCommand event handler, Page PreRender, SaveState etc... events are not triggered.Now if i implement what you have suggested, what happens the All the events of Asp.Net Page gets triggered.void ItemCommand(...) {Response.Redirect("Detail.aspx", false);  /// Notice i am passing the endResponse flag as false.this.Context.ApplicationInstance.CompleteRequest();}There are some code written in PreRender method, is there a way to know that the CompleteRequest method is called like some flag or any Property.Please advice.
  • Anonymous
    November 18, 2010
    Great question!  I don't know the answer, but I've passed the question on to someone who does and will post it here when I get a response.
  • Anonymous
    November 22, 2010
    The answer to your question is that ASP.NET does not expose an indicator as to whether or not CompleteRequest was called.Quoting from Thomas Marquardt's response:"CompleteRequest causes the 'pipeline' to jump ahead to the EndRequest event, but this only happens after the current HttpApplication event completes.  Frequently the code that runs in the current HttpApplication event, after you call CompleteRequest, does not harm anything.  In the case here, the page handler continues to run, so all the page events will fire.  If that is causing harm, and you can’t mitigate that by remembering whether or not you called CompleteRequest, then you may need to use Response.Redirect(url, true) instead."
  • Anonymous
    April 14, 2011
    The page blogs.msdn.com/.../response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx still does not contain the info from Marquardt's explanation, regarding the pipeline.It's still not clear.  Also that page should include links to response.End() and Response.Close() and an explanation of when to use what.  The same decision tree should be in the doc page for those 2 other calls.
  • Anonymous
    May 13, 2011
    Further details on how to skip the rest of the pipeline when using CompleteRequest: stackoverflow.com/.../3917180
  • Anonymous
    July 04, 2011
    Apparently there are situations when you have to use Response.End(), otherwise ASP.NET will append tags in the response. blogs.msdn.com/.../excel-found-unreadable-content-in-workbook-do-you-want-to-recover-the-contents-of-this-workbook.aspxThis also appears to be implied by MS KB:support.microsoft.com/.../306654support.microsoft.com/.../307603
  • Anonymous
    January 23, 2012
    Just want you folks to know that the information presented here should not be used - which I unfortunately did and found out the hard way.Using Response.End() when attempting to open and download a PDF works, change it to this.Context.ApplicationInstance.CompleteRequest() and you start getting 'File is damaged or corrupt' errors. It is a shame that by following the so called gurus I broke my application.
  • Anonymous
    June 24, 2012
    It is nice
  • Anonymous
    October 16, 2012
    The comment has been removed
  • Anonymous
    August 14, 2013
    I work for a client and another developer recently changed the code in a custom 301 redirect that we use, from Response.End to CompleteRequest, and now we are having a problem while running in integrated pipeline, of Application Instance can not be changed.. On a test machine, I have two choices.  If I change it to Classic Mode, the error doesn't come up, or I can change it back to Response.End and it works fine in Integrated Pipeline Mode.  Is anyone else having a problem similar to this, with a custom written 301?
  • Anonymous
    September 12, 2013
    Really helpful, similar defect has been met and data lost by using HttpResponse.Close
  • Anonymous
    December 13, 2013
    The comment has been removed
  • Anonymous
    June 26, 2014
    Thank you Tom, that was very helpful. For other people out there struggling with Chrome reporting net::ERR_INCOMPLETE_CHUNKED_ENCODING after Response.End() or Response.Close(), this is the solution to your problem.
  • Anonymous
    May 19, 2015
    The only way this would make sense is if it was HttpResponse.CompleteRequest, not HttpApplication.  HttpResponse needs to return to the complete the page.