由Response.Redirect引起的System.Threading.ThreadAbortException

Tap*_*ose 4 c# asp.net exception response webmethod

在我的应用程序中,我从JavaScript调用WebMethod,我试图重定向到某个页面:

[WebMethod]
public string Logout() {            
    if (User.Identity.IsAuthenticated) {                            
        HttpContext.Current.Response.Redirect("~/Pages/Logout.aspx");               
    }
    return "";
}
Run Code Online (Sandbox Code Playgroud)

aspx页面:

    <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>
Run Code Online (Sandbox Code Playgroud)

我得到了:

mscorlib.dll中出现'System.Threading.ThreadAbortException'类型的第一次机会异常

mscorlib.dll中出现"System.Threading.ThreadAbortException"类型的异常,但未在用户代码中处理

在我的VS2010的输出窗口中.

为什么我会收到此异常,如何解决此问题?

Sam*_*Sam 9

重定向的理想方式是调用Response.Redirect(someUrl, false)然后调用CompleteRequest()

传递false Response.Redirect(...)将阻止ThreadAbortException引发,但是通过调用结束页面生命周期仍然很重要CompleteRequest().

在页面处理程序中使用此方法终止对一个页面的请求并为另一个页面启动新请求时,请将endResponse设置为false,然后调用CompleteRequest()方法.如果为endResponse参数指定true,则此方法为原始请求调用End方法,该方法在完成时抛出ThreadAbortException异常.此异常对Web应用程序性能有不利影响,这就是建议为endResponse参数传递false的原因.有关更多信息,请参阅End方法.

请注意,Response.Redirect(...)调用该方法时,会生成一个具有全新页面生命周期的新线程,以处理新的重定向响应.当新响应完成时,它会调用Response.End()原始响应,最终会抛出ThreadAbortException并响应EndRequest事件.如果你阻止Response.End()被调用(通过传递false Response.Redirect),那么你需要调用CompleteRequest()哪个:

导致ASP.NET绕过所有事件并在HTTP管道执行链中进行过滤,并直接执行EndRequest事件.

谨慎之言:

如果您调用Response.Redirect(someUrl, false)允许代码继续执行,您可能希望更改代码,以便处理正常停止.有时这就像添加return一个void方法调用一样简单.但是,如果你是一个深度调用堆栈,这是更棘手的,如果你不想要更多的代码执行它可能更容易传递真实,Response.Redirect(someUrl, true)并故意期望ThreadAbortException- 顺便说一句,这不是一件坏事,你应该期待它Response.Redirect(...)Server.Transfer(...)电话.

捕获异常无法停止ThreadAbortException

ThreadAbortException不是普通的异常.即使将代码包装在try catch块中,ThreadAbortException也会在finally子句之后立即引发.

当调用Abort方法来销毁线程时,公共语言运行库会抛出ThreadAbortException. ThreadAbortException是一个可以捕获的特殊异常,但它会在catch块的末尾自动再次引发.引发此异常时,运行时会在结束线程之前执行所有finally块.因为线程可以在finally块中执行无限制计算或调用Thread.ResetAbort来取消中止,所以无法保证线程将永远结束.如果要等到中止的线程结束,可以调用Thread.Join方法.Join是一个阻塞调用,在线程实际停止执行之前不会返回.

通常我在代码中看到的是一个围绕Response.Redirect的try catch块,它将记录不是ThreadAbortExceptions的异常(因为你期望那些).例:

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);
   }
}
Run Code Online (Sandbox Code Playgroud)