In my application I am calling a WebMethod from JavaScript, where I am trying to redirect to some page:
[WebMethod]
public string Logout() {
if (User.Identity.IsAuthenticated) {
HttpContext.Current.Response.Redirect("~/Pages/Logout.aspx");
}
return "";
}
The aspx page:
<input onclick="callLogout();" id="btn" type="button" value="Click Me" />
<asp:ScriptManager ID="ScriptManager" runat="server">
<Services>
<asp:ServiceReference Path="~/WebServices/EMSWebService.asmx" />
</Services>
</asp:ScriptManager>
<script type="text/javascript">
function callLogout() {
EMSApplication.Web.WebServices.EMSWebService.Logout(OnComplete, OnError);
}
function OnComplete(result) {
alert(result);
}
function OnError(result) {
alert(result.get_message());
}
</script>
And I am getting:
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll
An exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll but was not handled in user code
in my VS2010's Output window.
Why I am getting this exception and how can I resolve this?
Response.Redirect(someUrl, false)
and then call CompleteRequest()
Passing false to Response.Redirect(...)
will prevent the ThreadAbortException
from being raised, however it is still important to end the page lifecycle by calling CompleteRequest()
.
When you use this method in a page handler to terminate a request for one page and start a new request for another page, set endResponse to false and then call the CompleteRequest() method. If you specify true for the endResponse parameter, this method calls the End method for the original request, which throws a ThreadAbortException exception when it completes. This exception has a detrimental effect on Web application performance, which is why passing false for the endResponse parameter is recommended. For more information, see the End method.
Note that when the Response.Redirect(...)
method is called, a new thread is spawned with a brand new page lifecycle to handle the new redirected response. When the new response finishes, it calls Response.End()
on the original response which eventually throws a ThreadAbortException
and raises the EndRequest
event. If you prevent Response.End()
from being called (by passing false to Response.Redirect
) then you need to call CompleteRequest()
which:
Causes ASP.NET to bypass all events and filtering in the HTTP pipeline chain of execution and directly execute the EndRequest event.
If you call Response.Redirect(someUrl, false)
allowing code continue to execute, you may want to change your code such that the processing gracefully stops. Sometimes this is as easy as adding a return
to a void method call. However, if you are in a deep call stack, this is much trickier and if you don't want more code executing it might be easier to pass true like Response.Redirect(someUrl, true)
and purposely expect the ThreadAbortException
- which by the way isn't a bad thing, you should expect it during Response.Redirect(...)
and Server.Transfer(...)
calls.
The ThreadAbortException is not your ordinary exception. Even if you wrap your code in a try catch block, the ThreadAbortException will immediately be raised after the finally clause.
When a call is made to the Abort method to destroy a thread, the common language runtime throws a ThreadAbortException. 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 ending the thread. Because the thread can do an unbounded computation in the finally blocks or call Thread.ResetAbort to cancel the abort, there is no guarantee that the thread will ever end. If you want to wait until the aborted thread has ended, you can call the Thread.Join method. Join is a blocking call that does not return until the thread actually stops executing.
Often what I've seen in code is a try catch block around Response.Redirect that will log exceptions that are not ThreadAbortExceptions (since you expect those). Example:
private void SomeMethod()
{
try
{
// Do some logic stuff
...
if (someCondition)
{
Response.Redirect("ThatOneUrl.aspx", true);
}
}
catch (ThreadAbortException)
{
// Do nothing.
// No need to log exception when we expect ThreadAbortException
}
catch (Exception ex)
{
// Looks like something blew up, so we want to record it.
someLogger.Log(ex);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With