为什么Response.Redirect导致System.Threading.ThreadAbortException?

Ben*_*man 227 c# asp.net .net-3.5

当我使用Response.Redirect(...)将表单重定向到新页面时,我收到错误:

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

我对此的理解是,错误是由Web服务器中止调用response.redirect的页面的其余部分引起的.

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

Joe*_*ore 329

正确的模式是使用endResponse = false调用Redirect重载并调用告诉IIS管道,一旦返回控件,它应该直接前进到EndRequest阶段:

Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();
Run Code Online (Sandbox Code Playgroud)

Thomas Marquardt的这篇博客文章提供了其他详细信息,包括如何处理Application_Error处理程序内部重定向的特殊情况.

  • 我认为说"第二次重载"而不是你在评论中使用的"旧版Redirect"短语更准确,它不像MS改变了实现,它只是另一种重载. (12认同)
  • 它在`Context.ApplicationInstance.CompleteRequest();`之后执行代码.为什么?我是否必须有条件地从事件处理程序"返回"? (6认同)
  • @Ismail:旧版本的Redirect抛出ThreadAbortException以防止执行任何后续代码.较新的首选版本不会抛出,但如果您在处理程序中有其他代码,则负责尽早返回控制. (4认同)
  • 我认为这不是理想的模式。您要页面不结束响应并继续执行,然后以编程方式完成请求。但是,aspx页面和事件处理程序的呈现方式又如何呢?没有结束响应,它将在点击“ completeRequest()”之前完成渲染aspx页面。现在,如果我在页面中使用服务器端属性,请说一个会话变量来确定有效的登录名,如果该登录名到期,将在重定向之前引发null异常。解决此问题的唯一方法是使endResponse恢复为true。 (2认同)

Jac*_*esB 154

没有简单而优雅的解决Redirect在ASP.Net WebForms的问题.您可以选择Dirty解决方案和Tedious解决方案

: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在控制器中返回a 而不生成视图来进行干净的重定向.

  • 我喜欢这个答案中的细节.**比接受的答案更好** (8认同)
  • 我相信我曾经听过的最好的网络形态描述是"撒谎". (5认同)

Ort*_*und 31

我知道我已经迟到了,但如果我Response.Redirect在一个Try...Catch街区,我只会遇到这个错误.

永远不要将Response.Redirect放入Try ... Catch块.这是不好的做法

编辑

为了回应@Kiquenet的评论,我将做的是将Response.Redirect放入Try ... Catch块的替代方案.

我将方法/功能分解为两个步骤.

Try ... Catch块中的第一步执行请求的操作并设置"结果"值以指示操作的成功或失败.

Try ... Catch块之外的第二步是重定向(或不重定向),具体取决于"结果"值是什么.

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

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


M4N*_*M4N 8

Response.Redirect() 抛出异常以中止当前请求.

知识库文章描述了此行为(也适用于Request.End()Server.Transfer()方法).

因为Response.Redirect()存在过载:

Response.Redirect(String url, bool endResponse)
Run Code Online (Sandbox Code Playgroud)

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

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


Mar*_*ith 7

这就是Response.Redirect(url,true)的工作原理.它抛出ThreadAbortException以中止线程.只是忽略那个例外.(我认为它是一个全局错误处理程序/记录器,你在哪里看到它?)

一个有趣的相关讨论是否认为Response.End()有害?

  • 中止线程似乎是一种非常严厉的方式来处理过早的响应.我觉得很奇怪,框架不喜欢重新使用线程而不是旋转一个新的线程取而代之. (4认同)

spe*_*der 6

这是关于问题的官方路线(我找不到最新的,但我不认为以后版本的.net的情况已经改变)

  • @svick无论链接腐烂,链接只有答案不是真正的好答案.http://meta.stackexchange.com/q/8231`我认为这些链接太棒了,但它们永远不应该是你答案中唯一的信息. (4认同)