![](/img/trans.png)
[英]System.Threading.ThreadAbortException caused by Response.Redirect
[英]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 塊的替代方法,我將方法/函數分解為兩個步驟。
在 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.
}
}
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.