5 January 2011

ThreadAbortException on Response.Redirect(), Response.End() and Response.Transfer()

If you have ever used a call to Response.Redirect("url"), Response.End() or Server.Transfer() within a try block, you will probably have noticed that these calls always throw a ThreadAbortException.
This is normal behaviour, but can mess up your program if the corresponding catch is executed unexpectedly.
To avoid this, catch the ThreadAbortException in a separate catch, or write a try/catch around the call.
For instance, if you have:

try
{
    Do something here;
    
    Response.Redirect("some url");

    Do some more work;
}

catch(Exception ex)
{
    Do something useful with the excepion here;
}

You can rewrite it like so:


try
{
    Do something here;
    
    Response.Redirect("some url");

    Do some more work;
}
catch(ThreadAbortException ex) { } // Do nothing here, as we expected this exception.

catch(Exception ex)
{
    Do something useful with the excepion here;
}

Because the way exception handling works, any ThreadAbortException will get handled by the first catch, all the others by the next catch. The .NET framework looks for the first catch that matches the thrown exception and lets it handle it. Therefor, you always have to make sure that you put the more specific catches up front and the more general ones at the end.
Because the first catch handles the ThreadAbortException, the catch that handles the general Exception will not get called.
Be aware though that Do some more work; will not be executed, because execution will have skipped to the catch in stead.
If you want the Do some more work; part of the code to be executed, you can rewrite as follows:
try
{
    Do something here;

    try
    {
        Response.Redirect("some url");
    }
    catch(ThreadAbortException) { } // Do nothing here, as we expected this exception.

    Do some more work;
}

catch(Exception ex)
{
    Do something useful with the excepion here;
}

An other solution for Response.Redirect throwing this exception is using Response.Redirect("url", true). Be aware though, that this does not perform a call to Response.End(), so any following code can still access this Response and thus produce unwanted results.
In stead of Server.Transfer("url") you can use Server.Execute("url"). This will also execute the Do some more work; code, because control is not passed to the other page, the other page is executed and control is returned to the calling page.

I can write a post about the differences between Response.Redirect()Server.Transfer() and Server.Execute() if you are interested.


No comments :