为什么反应。重定向导致System.Threading.ThreadAbortException?

当我使用Response.Redirect(…)将我的表单重定向到一个新页面时,我得到了错误:

System.Threading类型的第一次机会异常。mscorlib.dll
.dll中出现ThreadAbortException' System.Threading类型的异常。在mscorlib.dll中发生ThreadAbortException',但在用户代码

.dll中没有处理

我对此的理解是,该错误是由web服务器中止余下的页面响应引起的。重定向被调用。

我知道我可以向Response.Redirect添加第二个参数,称为endResponse。如果我将endResponse设置为True,我仍然会得到错误,但如果我将它设置为False,那么我就不会得到错误。我很确定,这意味着web服务器正在运行我重定向离开的页面的其余部分。至少可以这么说,这似乎效率很低。还有更好的办法吗?除了Response.Redirect之外的东西,或者有一种方法强制旧页面停止加载,在那里我不会得到ThreadAbortException?

157975 次浏览

下面是关于这个问题的官方立场(我找不到最新的,但我不认为情况已经改变了。net的后续版本)

这就是Response.Redirect(url, true)的工作方式。它抛出ThreadAbortException来中止线程。忽略这个异常。(我假设它是一些全局错误处理程序/记录器,你看到它了吗?)

一个有趣的相关讨论。

Response.Redirect()抛出异常终止当前请求。

KB文章描述了这种行为(也适用于Request.End()Server.Transfer()方法)。

对于Response.Redirect(),存在重载:

Response.Redirect(String url, bool endResponse)

如果传递endResponse = false,则不会抛出异常(但运行时将继续处理当前请求)。

如果endResponse = true(或如果使用了其他重载),则抛出异常,当前请求将立即终止。

正确的模式是使用endResponse=false调用重定向重载,并调用IIS管道,一旦你返回控制,它应该直接进入EndRequest阶段:

Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();

Thomas Marquardt的这篇博文提供了额外的细节,包括如何处理Application_Error处理程序内部重定向的特殊情况。

我也有这个问题。

试着用Server.Transfer代替Response.Redirect

为我工作。

我知道我迟到了,但只有当我的Response.Redirect位于Try...Catch块中时,我才会遇到这种错误。

永远不要放一个响应。重定向到尝试…Catch块。这是不好的做法

作为放置响应的替代方法。重定向到尝试…Catch块,我将把方法/函数分解为两个步骤。

  1. within the Try…Catch块执行所请求的操作,并设置一个"result"值,以指示操作的成功或失败。

  2. outside of the Try…Catch块是否重定向取决于"result"价值是多少。

这段代码远非完美,可能不应该复制,因为我还没有测试过它

public void btnLogin_Click(UserLoginViewModel model)
{
bool ValidLogin = false; // this is our "result value"
try
{
using (Context Db = new Context)
{
User User = new User();


if (String.IsNullOrEmpty(model.EmailAddress))
ValidLogin = false; // no email address was entered
else
User = Db.FirstOrDefault(x => x.EmailAddress == model.EmailAddress);


if (User != null && User.PasswordHash == Hashing.CreateHash(model.Password))
ValidLogin = true; // login succeeded
}
}
catch (Exception ex)
{
throw ex; // something went wrong so throw an error
}


if (ValidLogin)
{
GenerateCookie(User);
Response.Redirect("~/Members/Default.aspx");
}
else
{
// do something to indicate that the login failed.
}
}

对于ASP中的Redirect问题,有没有简单而优雅的解决方案。净WebForms。你可以在解决方案和单调乏味的解决方案之间进行选择

: Response.Redirect(url)向浏览器发送重定向,然后抛出ThreadAbortedException来终止当前线程。因此,在Redirect()调用之后不会执行任何代码。缺点:像这样杀死线程是一种糟糕的做法,会影响性能。此外,ThreadAbortedExceptions将显示在异常日志记录中。

单调乏味的:推荐的方法是调用Response.Redirect(url, false),然后调用Context.ApplicationInstance.CompleteRequest()。然而,代码将继续执行,并且页面生命周期中的其余事件处理程序仍将执行。(例如,如果你在Page_Load中执行重定向,不仅处理程序的其余部分会被执行,Page_PreRender等也会被调用——呈现的页面不会被发送到浏览器。你可以避免额外的处理,例如在页面上设置一个标志,然后让后续的事件处理程序在做任何处理之前检查这个标志。

(CompleteRequest的文档声明它是“导致ASP。NET来绕过HTTP管道执行链中的所有事件和过滤”。这很容易被误解。它确实会绕过进一步的HTTP过滤器和模块,但它不会绕过当前页面生命周期中的进一步事件。)

更深层次的问题是WebForms缺乏抽象级别。当您处于事件处理程序中时,您已经处于构建要输出的页面的过程中。在事件处理程序中重定向是丑陋的,因为您要终止部分生成的页面以生成不同的页面。MVC没有这个问题,因为控制流与呈现视图是分开的,所以你可以通过简单地在控制器中返回RedirectAction来进行干净的重定向,而不生成视图。

我要做的就是捕捉这个异常,以及其他可能的异常。希望这能帮助到一些人。

 catch (ThreadAbortException ex1)
{
writeToLog(ex1.Message);
}
catch(Exception ex)
{
writeToLog(ex.Message);
}

我也尝试了其他解决方案,但一些代码执行后重定向。

public static void ResponseRedirect(HttpResponse iResponse, string iUrl)
{
ResponseRedirect(iResponse, iUrl, HttpContext.Current);
}


public static void ResponseRedirect(HttpResponse iResponse, string iUrl, HttpContext iContext)
{
iResponse.Redirect(iUrl, false);


iContext.ApplicationInstance.CompleteRequest();


iResponse.BufferOutput = true;
iResponse.Flush();
iResponse.Close();
}

所以如果需要防止代码执行后重定向

try
{
//other code
Response.Redirect("")
// code not to be executed
}
catch(ThreadAbortException){}//do there id nothing here
catch(Exception ex)
{
//Logging
}

我甚至试图避免这一点,以防万一在线程上手动做中止,但我宁愿留下它与“CompleteRequest”和继续-我的代码有返回命令后重定向无论如何。这是可以做到的

public static void Redirect(string VPathRedirect, global::System.Web.UI.Page Sender)
{
Sender.Response.Redirect(VPathRedirect, false);
global::System.Web.UI.HttpContext.Current.ApplicationInstance.CompleteRequest();
}