Georged Weblog

Have you georged your mind?

Stepping on a rake

Whammm! I did it again! How many times do I have to tell myself that Response.Redirect(string) throws an ThreadAbortException?! Here is the short version:

private void Page_Load(object sender, System.EventArgs e)
{
   try
   {
      Response.Redirect("page1.aspx");
   }
   catch
   {
      Response.Redirect("page2.aspx");
   }
}

As expected(?), browser ends up on page2.aspx. So far so good but let’s do something smart and catch the exception (ignoring decoding/encoding and other mundane stuff):

private void Page_Load(object sender, System.EventArgs e)
{
   try
   {
      Response.Redirect("page1.aspx");
   }
   catch (Exception ex)
   {
      Response.Redirect("page2.aspx?error=" + ex.ToString());
   }
}

Browser ends up on page1.aspx?! Now that’s weird. Peeking in IL source with Reflector failed to reveal any substantial differences between the two. The answer, I guess, is buried somewhere inside HttpResponse.End and Thread.Abort methods which is more than my brain can digest. Explanation, anyone?

Note to myself: never place Redirect inside try{} block but if you have to, make sure it looks like this:

private void Page_Load(object sender, System.EventArgs e)
{
   try
   {
      Response.Redirect("page1.aspx", false);
      return;
   }
   catch (Exception ex)
   {
      Response.Redirect("page2.aspx?error=" + ex.ToString());
   }
}

Posted: Jun 10 2003, 01:22 AM by georged | with 6 comment(s)
Filed under:

Comments

Scott Galloway said:

You've just solved a mystery for me...not if only I could get a try...catch.. block to catch all exceptions except those of a certain type...
# June 9, 2003 3:17 PM

Julien Ellie said:

This IS weird. But honestly I dont mean to be condescending in any way but catch (Exception) is poor practice in any case. Nice code catch only typed exception and you can implement the global.asax OnException to catch the one that go all the way up.
# June 9, 2003 3:33 PM

George Doubinski said:

Julien, you're right, catching generic Exception *is* a bad practice - that was done only to illustrate the point. The actual code is far more complicated and it took me a while to isolate the problem.
I was trying to make a point that Response.Redirect throws an exception and a very special one: a) ThreadAbortException gets raised again at the end of the catch block and b) it gets silently swallowed by the framework later on.
# June 10, 2003 6:33 AM

Palo Mraz said:

You can call the HttpResponse.Redirect(string, boolean) overload and pass 'false' as the value of the second argument. This will prevent the HttpResponse.End method to be called...

PS: Found this on my quest to solve another ThreadAbortException mystery :-) ... will post an article about this on my site...
# September 26, 2003 7:18 AM

Greg Christie said:

I think the reason the first catch block is executed is because you never actually try to capture the ThreadAbortException object into an Exception and so .net doesn't stop it from getting through. The code to block that error must exist within the method that formats the exception object and presents it to the catch block.

Just a thought
# December 3, 2003 5:01 PM

Panayot Belchev said:

This exception is normal and is necessary for the runtime. I would suggest this code:

try
{
Response.Redirect("page.aspx");
}
catch(System.Threading.ThreadAbortException)
{
//do nothing
}
catch(Exception exc)
{
//process all other exceptions here
}

ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. When this exception is raised, the runtime executes all the finally blocks before killing the thread.
# January 21, 2004 6:42 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)