首页 文章

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

提问于
浏览
214

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

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

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

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

10 回答

  • 7

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

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

    Thomas Marquardt的This blog post提供了其他详细信息,包括如何处理Application_Error处理程序内部重定向的特殊情况 .

  • 6

    ASP.Net WebForms中的 Redirect 问题有 no 简单而优雅的解决方案 . 您可以在 Dirty 解决方案和 Tedious 解决方案之间进行选择

    DirtyResponse.Redirect(url) 向浏览器发送重定向,然后抛出 ThreadAbortedException 以终止当前线程 . 因此,没有代码执行Redirect() - 调用 . 缺点:这是一种不好的做法,并且会对杀死这样的线程产生影响 . 此外, ThreadAbortedExceptions 将显示在异常日志记录中 .

    Tedious :建议的方法是调用 Response.Redirect(url, false) 然后调用 Context.ApplicationInstance.CompleteRequest() 但是,代码执行将继续,页面生命周期中的其余事件处理程序仍将执行 . (例如,如果您在Page_Load中执行重定向,则不仅会执行处理程序的其余部分,还会调用Page_PreRender等等 - 渲染的页面将不会被发送到浏览器 . 您可以避免额外的处理例如,在页面上设置一个标志,然后让后续事件处理程序在进行任何处理之前检查此标志 .

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

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

  • 1

    我知道如果我的 Response.RedirectTry...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.
        }
    }
    
  • 8

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

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

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

    Response.Redirect(String url, bool endResponse)
    

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

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

  • 0

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

    一个有趣的相关讨论Is Response.End() considered harmful?

  • 1

    这是关于问题的official line(我不能认为.net的更高版本的情况已经发生了变化)

  • 2

    我甚至试图避免这种情况,以防万一在线程上手动执行Abort,但我宁愿将其保留为“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();
    }
    
  • 28

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

    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
    }
    
  • 144

    我所做的是捕获此异常,以及另一个可能的例外 . 希望这能有所帮助 .

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

    我也有这个问题 . 尝试使用Server.Transfer而不是Response.Redirect为我工作

相关问题