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

时间:2012-04-01 13:09:07

标签: c# asp.net exception response webmethod

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

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

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>

我得到了:

  

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

     

发生了'System.Threading.ThreadAbortException'类型的异常   mscorlib.dll但未在用户代码中处理

在我的VS2010的输出窗口中。

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

3 个答案:

答案 0 :(得分:9)

重定向的理想方法是致电Response.Redirect(someUrl, false),然后致电CompleteRequest()

将false传递给Response.Redirect(...)会阻止ThreadAbortException被提升,但是通过调用CompleteRequest()来结束页面生命周期仍然很重要。

  

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

请注意,调用Response.Redirect(...)方法时,会生成一个具有全新页面生命周期的新线程,以处理新的重定向响应。新响应完成后,会在原始响应上调用Response.End(),最终会引发ThreadAbortException并引发EndRequest事件。如果您阻止调用Response.End()(通过将false传递给Response.Redirect),则需要致电CompleteRequest(),其中包含:{/ p>

  

使ASP.NET绕过HTTP管道中的所有事件和过滤   执行链并直接执行EndRequest事件。

警告:

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

通过捕获异常无法停止ThreadAbortException

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

  

当调用Abort方法来销毁一个线程时,   公共语言运行库抛出ThreadAbortException。    ThreadAbortException是一个可以捕获的特殊异常,但它   将在catch块结束时再次自动引发。什么时候   引发此异常,运行时执行所有finally块   在结束线程之前。因为线程可以做无界限   在finally块中计算或调用Thread.ResetAbort来取消   中止,无法保证线程永远不会结束。如果你   想要等到中止的线程结束,你可以调用   Thread.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);
   }
}

答案 1 :(得分:0)

这是由Response.Redirect引起的标准异常,只有当您对执行重定向的块有明确try-catch时才会捕获。 ASP.NET在重定向时抛出它,以便在重定向后不执行代码。

解决方案是添加一个空捕获以吞下此特定异常

try {
   ...
   Response.Redirect( ... );
}
catch ( ThreadAbortException ) { } // swallow the exception
catch ( Exception ex ) { 
   // an existing catch clause
}

答案 2 :(得分:0)

不要只是抓住异常。使用带有布尔值的Redirect重载。传递false表示您不希望线程中止。