Why Response.Redirect causes System.Threading.ThreadAbortException?
当我使用response.redirect(…)将表单重定向到新页面时,会收到错误:
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll
An exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll but was not handled in user code
我对此的理解是,错误是由Web服务器中止调用response.redirect的页面的其余部分引起的。
我知道我可以向
正确的模式是调用endResponse=false的重定向重载,并进行调用,告诉IIS管道,一旦返回控件,它应该直接前进到endRequest阶段:
1 2 | Response.Redirect(url, false); Context.ApplicationInstance.CompleteRequest(); |
ThomasMarquardt的这篇博客文章提供了更多的细节,包括如何处理应用程序错误处理程序中重定向的特殊情况。
对于ASP.NET WebForms中的
脏:
乏味:建议的方法是调用
(
更深层的问题是,WebForms缺乏抽象层次。当您在事件处理程序中时,您已经在构建要输出的页面的过程中。在事件处理程序中重定向是丑陋的,因为您要终止部分生成的页面以生成不同的页面。MVC没有这个问题,因为控制流与呈现视图是分开的,所以您可以通过简单地在控制器中返回
我知道我迟到了,但我只有在我的
永远不要放响应。重定向到一个try…catch块。这是不好的做法
编辑作为对@kiquenet评论的回应,下面是我将要做的作为放置响应的替代方法。重定向到try…catch块。
我将把方法/函数分解为两个步骤。
Try…Catch块中的步骤1执行请求的操作,并设置"result"值以指示操作的成功或失败。
Try…Catch块之外的步骤2根据"result"值进行重定向(或不重定向)。
这段代码还远远不够完美,可能不应该复制,因为我还没有测试过它
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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. } } |
这篇知识库文章描述了这种行为(也适用于
对于
1 | Response.Redirect(String url, bool endResponse) |
如果传递endResponse=false,则不会引发异常(但运行时将继续处理当前请求)。
如果endResponse=true(或者使用了其他重载),则抛出异常,当前请求将立即终止。
这就是response.redirect(url,true)的工作原理。它抛出threadabortexception以中止线程。忽略那个例外。(我假设您看到的是某个全局错误处理程序/记录器?)
一个有趣的相关讨论是response.end()被认为有害吗?
这是关于这个问题的官方说法(我找不到最新版本,但我认为.NET的更新版本不会改变这种情况)。
我甚至试图避免这种情况,以防手动中止线程,但我宁愿把它放在"completeRequest"中,继续前进-我的代码在重定向之后仍然有返回命令。这样就可以做到
1 2 3 4 5 | 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(); } |
我还尝试了其他的解决方案,但是在重定向之后执行了一些代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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(); } |
因此,如果需要在重定向后阻止代码执行
1 2 3 4 5 6 7 8 9 10 11 | try { //other code Response.Redirect("") // code not to be executed } catch(ThreadAbortException){}//do there id nothing here catch(Exception ex) { //Logging } |
我要做的是捕获这个异常,以及其他可能的异常。希望这能帮助别人。
1 2 3 4 5 6 7 8 | catch (ThreadAbortException ex1) { writeToLog(ex1.Message); } catch(Exception ex) { writeToLog(ex.Message); } |
我也有那个问题。尝试使用Server.Transfer而不是Response.Redirect为我工作