40

Within an ASPX page, I want to end the response at specific points (not due to an error condition), depending on code path, so that nothing else is sent back down the stream. So naturally used:

Response.End();

This results in a ThreadAbortException, which is by design.

The following seems to work but does not look like the correct approach as per this SO question:

Response.Flush();
Response.Close();

So, how about this?

Response.Flush();
Response.SuppressContent = true

and then just let the page complete normally.

I could just handle and swallow the ThreadAbortException, but I just want to find out if there is anything wrong/gotchas with the SuppressContent approach?

Edit: To give a bit more of an example. Say I have a ASPX page whereby I may change the content-type to one of a number of possibilities. Depending on the content-type and scenario, at a given point in the code I want to prevent any more content from being sent to the client. Assume after SuppressContent has been set set to true, that there is no issue with any further server-side code running. I just don't want anything else to be sent to the client.

Edit 2: MyPage.aspx - has a master page which may include standard content, headers, footers etc etc. This page can just render as a normal page. It also can just write out an (e.g.) XML document to be downloaded. If writing out an XML document (determined on page load), it will clear the ouput, set the content-type to XML, write all the XML out and then if left normally, you end up with the rest of the ASPX page rendering being tacked on to the end - that is obviously not required/breaks the XML.

Edit 3: For now I'm using the SuppressContent approach. To try and draw this question to a close, I'm raising a bounty and will put the question another way: When should you use SuppressContent? Why would you use it instead of Response.End?


Please see the answer I provided below for the solution I actually ended up with as I eventually found a way to avoid the ThreadAbortException when using Response.End. I had already excepted an answer by this point.


Community
  • 1
  • 1
AdaTheDev
  • 142,592
  • 28
  • 206
  • 200
  • It sounds like you need to carefully examine your code to see what else could be writing out to the response stream after you've finished. This all has the sound of being a teensy bit "spaghetti". – Jeremy McGee Dec 11 '09 at 13:51
  • There are no other Response.Writes or anything from the code behind. The problem is that if the page actually writes out an XML document instead of the normal HTML page output, once I've changed the content-type to XML and written the XML out, I don't want the remainder of the ASPX page to be rendered - that would obviously break the XML – AdaTheDev Dec 11 '09 at 13:59
  • Note that you can always change the accepted answer, even now, 11 years later... – Heretic Monkey Jun 29 '20 at 15:20

6 Answers6

48

I know this is an old question, but I'm including this for the benefit of anyone who might stumble into this post. I've been chasing down a bug that led me to review my use of Response.End, and discovered an MSDN post from a year after this question that could be summarized as "Never, ever use Response.End". Here's what Thomas Marquardt, who designed the Integrated Pipeline for IIS7, says about it:

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.

From http://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx

Eyeball
  • 1,322
  • 2
  • 16
  • 26
  • 6
    Great find. This should definitively be the accepted answer. – Igor Brejc Jun 08 '14 at 16:24
  • +1 interesting find. I will definitely be using CompleteRequest the next time I ran into this scenario. Care must be taken, as it is not the same behavior as to what code gets executed after the call "and code after the call to the CompleteRequest method might be executed". Just a minor thing to pay attention to. – eglasius Jun 10 '14 at 07:08
  • +1 this solved the problem for me too. I had two issues contributing to it, which both needed to be solved, so if anybody applies this and it does not help, consider this: http://stackoverflow.com/questions/15586309/asp-net-mvc-4-api-download-of-docx-failing-in-ie8/15687482#comment59166866_15687482 – Cee McSharpface Mar 02 '16 at 13:44
  • 3
    This should probably be combined with Response.SuppressContent so people don't go accidentally updating your response, say in some module as suggested by @DanielCuadra here: http://stackoverflow.com/a/36968241/420667 – user420667 Jul 15 '16 at 19:12
12

I eventually found a simple solution to using Response.End() without getting a ThreadAbortException.

Response.Flush();
Response.End();

From my original question, I'd always been trying JUST a Response.End() after sending some content to the response stream.

It seems that if there is unflushed content when you do Response.End(), you get the ThreadAbortException. By doing the Flush immediately before the End, a ThreadAbortException does not actually get thrown.

Seems to be working great - no ThreadAbortException is being thrown now when I use Response.End

AdaTheDev
  • 142,592
  • 28
  • 206
  • 200
  • 8
    I have up-voted this answer, but after actually testing it I found out that this does not work. To test it yourself: In your code-behind wrap the Response.End in a try catch block and inside the catch block do a response.write(ex.Message). You will see a "Thread was being aborted." message. Still, looks like there is no other way to end response AND stop the code-behind execution, so just wrap your code behind in try catch and inside the catch do Server.ClearError(); *P.S. I am not sure what will be the actual point of this...* – Registered User Jul 12 '12 at 01:10
  • 2
    The exception *is* thrown, and anyway the first thing End() does is a flush* so I don't see how this would make a difference. And it doesn't. *"Sends all currently buffered output to the client" http://msdn.microsoft.com/en-us/library/system.web.httpresponse.end%28VS.80%29.aspx – mhenry1384 Oct 18 '12 at 21:38
  • I also just tested this. I think Response.End always throws an exception unless the context is not still in the cancellable period, whatever that means. http://referencesource.microsoft.com/#System.Web/HttpResponse.cs,4a66c734706db954 – user420667 Jul 15 '16 at 19:06
  • 1
    Also tested and the ThreadAbortException is still thrown in catch after Flush() then End() – Tikhon Sep 21 '17 at 18:15
4

update - warning: there is a better method, don't use this, see Ethan's answer instead!

I wouldn't say there is a valid reason to avoid the Response.End. Wanting to avoid the cost of the ThreadAbortException, by letting the page request cycle go on and have it do extra work that isn't necessary doesn't seem right.

ThreadAbortException is a special type of exception meant to stop a thread from execution (its re-thrown automatically even if caught). That said, there are some scenarios where it could do harm (see community content added at the end of ThreadAbortException).

Unless you are in one of those scenarios you should stick to Response.End. Note that some usages around, do a SuppressContent & Response.End, I guess in cases that you want to avoid some stuff that would come from the internal Response.Flush.

eglasius
  • 35,831
  • 5
  • 65
  • 110
  • I think this sums up the overall picture I've been getting from looking into this. Had seen a couple of articles using the SuppressContent/Response.End approach. Pointing to the community content section at the link was also useful. – AdaTheDev Dec 14 '09 at 22:15
  • 4
    Make sure to read @Ethan's answer, you should never use `Response.End()`. – Igor Brejc Jun 08 '14 at 16:26
  • After reading it, I totally agree. Adding a note on the top of my answer. – eglasius Jun 10 '14 at 07:10
3

This is a very common question. And it is almost always a mistake to call anything except Response.End(). Here is the description of End() from MSDN:

Sends all currently buffered output to the client, stops execution of the page, and raises the EndRequest event.

This seems to be exactly what you want to do. And you will notice in the last part that it raises the EndRequest event. This means that after End() is called, all data is flushed to the client that has been written before the End(), the socket is closed, and resources are freed, and your program stops processing the request right away.

Community
  • 1
  • 1
Nick Berardi
  • 54,393
  • 15
  • 113
  • 135
  • 3
    Yeah a Response.End() does work for me EXCEPT the niggle that you always get the ThreadAbortException. This is not an exceptional code path that hits the Response.End(), so feels wrong that handling this exception becomes the norm. It got me thinking that "there must be another way" - hence I wanted to know whether there was any real issue using the SuppressContent approach. – AdaTheDev Dec 11 '09 at 13:39
1

What if, after calling Response.SuppressContent = true your page goes on to make changes to a record in the database?

kͩeͣmͮpͥ ͩ
  • 7,783
  • 26
  • 40
  • Yes further server-side code will get executed so could do more work, like do database work. In my case that's not an issue; I just don't want any more content to be written out to the response from that point on. – AdaTheDev Dec 11 '09 at 12:03
1

As far as I can understand the code when reflecting HttpResponse using the Flush/SuppressContent approach will make you vulnerable to code trying to do header changes after flush. Changing a header after flush will give a HttpException.

I would use Response.End() to be absolutely sure that nothing else could interfere with the response.

If you want to continue execution but also short circuit the http pipeline consider using Response.Flush() and HttpContext.Current.ApplicationInstance.CompleteRequest() like Response.End() does when the context is not in a cancellable period.

Fredrik Haglund
  • 2,578
  • 2
  • 17
  • 19
  • After I've done the flush/suppresscontent, there will not be any header changes. In reality there probably won't actually be anything else really going on. Except that if I'm writing out an XML document, and set the content-type accordingly, I really just want to prevent any further ASPX-page rendered content (that would break the XML I've already rendered out). – AdaTheDev Dec 11 '09 at 13:44
  • The CompleteRequest method doesn't seem to work btw. After that's called, more content is still written to the client (this is e.g. master page content that I don't want) – AdaTheDev Dec 11 '09 at 15:46