This KB Article says that ASP.NET's Response.End()
aborts a thread.
Reflector shows that it looks like this:
public void End()
{
if (this._context.IsInCancellablePeriod)
{
InternalSecurityPermissions.ControlThread.Assert();
Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
}
else if (!this._flushing)
{
this.Flush();
this._ended = true;
if (this._context.ApplicationInstance != null)
{
this._context.ApplicationInstance.CompleteRequest();
}
}
}
This seems pretty harsh to me. As the KB article says, any code in the app following Response.End()
will not be executed, and that violates the principle of least astonishment. It's almost like Application.Exit()
in a WinForms app. The thread abort exception caused by Response.End()
is not catchable, so surrounding the code in a try
...finally
won't satisfy.
It makes me wonder if I should always avoid Response.End()
.
Can anyone suggest, when should I use Response.End()
, when Response.Close()
and when HttpContext.Current.ApplicationInstance.CompleteRequest()
?
ref: Rick Strahl's blog entry.
Based on the input I've received, my answer is, Yes, Response.End
is harmful, but it is useful in some limited cases.
- use
Response.End()
as an uncatchable throw, to immediately terminate theHttpResponse
in exceptional conditions. Can be useful during debugging also. AvoidResponse.End()
to complete routine responses. - use
Response.Close()
to immediately close the connection with the client. Per this MSDN blog post, this method is not intended for normal HTTP request processing. It’s highly unlikely that you would have a good reason to call this method. - use
CompleteRequest()
to end a normal request.CompleteRequest
causes the ASP.NET pipeline to jump ahead to theEndRequest
event, after the currentHttpApplication
event completes. So if you callCompleteRequest
, then write something more to the response, the write will be sent to the client.
Edit - 13 April 2011
Further clarity is available here:
- Useful post on MSDN Blog
- Useful analysis by Jon Reid
TL;DR
Per MSDN, Jon Reid, and Alain Renon:
ASP.NET Performance - Exception Management - Write Code That Avoids Exceptions
ThreadAbortException Solution
Response.End and Response.Close are not used in normal request processing when performance is important. Response.End is a convenient, heavy-handed means of terminating request processing with an associated performance penalty. Response.Close is for immediate termination of the HTTP response at the IIS/socket level and causes issues with things like KeepAlive.
The recommended method of ending an ASP.NET request is HttpApplication.CompleteRequest. Keep in mind that ASP.NET rendering will have to be skipped manually since HttpApplication.CompleteRequest skips the rest of the IIS/ASP.NET application pipeline, not the ASP.NET Page pipeline (which is one stage in the app pipeline).
Code
Copyright © 2001-2007, C6 Software, Inc as best I could tell.
Reference
HttpApplication.CompleteRequest
Response.End
Response.Close
If you had employed an exception logger on your app, it will be watered down with the
ThreadAbortException
s from these benignResponse.End()
calls. I think this is Microsoft's way of saying "Knock it off!".I would only use
Response.End()
if there was some exceptional condition and no other action was possible. Maybe then, logging this exception might actually indicate a warning.I disagree with the statement "Response.End is harmful". It's definitely not harmful. Response.End does what it says; it ends execution of the page. Using reflector to see how it was implemented should only be viewed as instructive.
My 2cent Recommendation
AVOID using
Response.End()
as control flow.DO use
Response.End()
if you need to stop request execution and be aware that (typically)* no code will execute past that point.*
Response.End()
and ThreadAbortExceptions.Response.End()
throws a ThreadAbortException as part of it's current implementation (as noted by OP).To see how to write code that must deal with ThreadAbortExceptions, see @Mehrdad's reply to SO How can I detect a threadabortexception in a finally block where he references RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup Method and Constrained Execution Regions
The Rick Strahl article mentioned is instructive, and make sure to read the comments as well. Note that Strahl's issue was specific. He wanted to get the data to the client (an image) and then process hit-tracking database update that didn't slow down the serving of the image, which made his the problem of doing something after Response.End had been called.
This question appears near the top of all google searches for information on response.end so for other searches like myself who wish to post CSV/XML/PDF etc in response to an event without rendering the entire ASPX page, this is how I do it. (overriding the render methods is overly complex for such a simple task IMO)
On the question of "I still don't know the difference between Response.Close and CompleteRequest()" I would say:
Do prefer CompleteRequest(), don't use Response.Close().
See the following article for a well-done summary of this case.
Be aware that even after calling CompleteRequest() some text (e.g. redndered from ASPX code) would be appended to the response output stream. You can prevent it by overriding Render and RaisePostBackEvent methods as described in the following article.
BTW: I agree with preventing of using Response.End(), especially when writing data to the http stream to emulate file download. We've used the Response.End() in the past until our log file became full of ThreadAbortExceptions.
I've used Response.End() in both .NET and Classic ASP for forcefully ending things before. For instance, I use it when there is a certian amount of login attempts. Or when a secure page is being accesed from an unauthenticated login (rough example):
When serving files to a user I'd use a Flush, the End can cause issues.