簡體   English   中英

為什么 Response.Redirect 會導致 System.Threading.ThreadAbortException?

[英]Why Response.Redirect causes System.Threading.ThreadAbortException?

當我使用 Response.Redirect(...) 將我的表單重定向到新頁面時,出現錯誤:

mscorlib.dll 中發生了“System.Threading.ThreadAbortException”類型的第一次機會異常
mscorlib.dll 中出現“System.Threading.ThreadAbortException”類型的異常,但未在用戶代碼中處理

我對此的理解是錯誤是由網絡服務器中止調用 response.redirect 的頁面的其余部分引起的。

我知道我可以向Response.Redirect添加第二個參數,稱為 endResponse。 如果我將 endResponse 設置為 True 我仍然會收到錯誤但如果我將它設置為 False 那么我不會。 我很確定這意味着網絡服務器正在運行我重定向的頁面的其余部分。 至少可以說這似乎是低效的。 有一個更好的方法嗎? Response.Redirect以外的東西,或者有沒有辦法強制舊頁面停止加載,我不會收到ThreadAbortException

正確的模式是使用 endResponse=false 調用重定向重載,並調用告訴 IIS 管道,一旦您返回控制權,它應該直接進入 EndRequest 階段:

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

Thomas Marquardt 的這篇博文提供了更多詳細信息,包括如何處理在 Application_Error 處理程序中重定向的特殊情況。

ASP.Net WebForms 中的Redirect問題沒有簡單而優雅的解決方案。 您可以在Dirty解決方案和Tedious解決方案之間進行選擇

Dirty : 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來做一個干凈的重定向,而不生成一個視圖。

我知道我遲到了,但只有當我的Response.Redirect位於Try...Catch塊中時才會出現此錯誤。

切勿將 Response.Redirect 放入 Try...Catch 塊中。 這是不好的做法

作為將 Response.Redirect 放入 Try...Catch 塊的替代方法,我將方法/函數分解為兩個步驟。

  1. 在 Try...Catch 塊內執行請求的操作並設置“結果”值以指示操作的成功或失敗。

  2. 在 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.
    }
}

Response.Redirect()拋出異常以中止當前請求。

這篇知識庫文章描述了這種行為(也適用於Request.End()Server.Transfer()方法)。

對於Response.Redirect()存在一個重載:

Response.Redirect(String url, bool endResponse)

如果傳遞endResponse=false ,則不會拋出異常(但運行時將繼續處理當前請求)。

如果endResponse=true (或者如果使用了其他重載),則拋出異常並立即終止當前請求。

這是有關該問題的官方線路(我找不到最新的,但我認為 .net 的更高版本的情況沒有改變)

這就是Response.Redirect(url, true)工作原理。 它拋出ThreadAbortException以中止線程。 只需忽略該異常。 (我認為這是一些全局錯誤處理程序/記錄器,您在哪里看到它?)

一個有趣的相關討論Response.End()是否被認為有害? .

我什至試圖避免這種情況,以防萬一手動在線程上執行 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();
}

我也嘗試了其他解決方案,但在重定向后執行了一些代碼。

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
}

我所做的是捕捉這個異常,以及其他可能的異常。 希望這有助於某人。

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

我也有這個問題。

嘗試使用Server.Transfer而不是Response.Redirect

為我工作。

我今天遇到了同樣的問題。在我的項目中,我有兩種類型的日志記錄頁面(簡單用戶和醫生用戶)。上周我完成了簡單的用戶日志記錄頁面,並且沒有任何問題。 本周我開始了醫生登錄頁面。 完成后,我再次檢查了簡單用戶登錄,發現它不起作用。 我跟蹤並意識到問題出在 response.redirect("simpleuser.aspx") (不要導航到 simpleuser.aspx)。 錯誤是(無法評估表達式,因為代碼已優化或本機框架位於調用堆棧頂部。)我通過互聯網檢查了所有解決方案,沒有運氣......甚至“response.redirect(URL,false)”我什么確實,我只是將 simpleuser.aspx 復制到另一個目錄....就是這樣。 完畢。 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM