当我使用Response.Redirect(...)将表单重定向到新页面时,我收到错误:
mscorlib.dll中出现'System.Threading.ThreadAbortException'类型的第一次机会异常
mscorlib.dll中出现“System.Threading.ThreadAbortException”类型的异常,但未在用户代码中处理
我对此的理解是,错误是由于网络服务器中止了调用response.redirect的页面的其余部分。
我知道我可以向Response.Redirect
添加一个名为endResponse的第二个参数。如果我将endResponse设置为True,我仍然会收到错误,但如果我将其设置为False,那么我不会。我很确定,这意味着网络服务器正在运行我重定向的页面的其余部分。至少可以说这似乎效率低下。有一个更好的方法吗?除Response.Redirect
以外的其他内容还是有办法强制旧页面停止加载我无法获得ThreadAbortException
的地方?
答案 0 :(得分:319)
正确的模式是使用endResponse = false调用Redirect重载并调用告诉IIS管道,一旦返回控件,它应该直接前进到EndRequest阶段:
Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();
来自Thomas Marquardt的This blog post提供了其他详细信息,包括如何处理在Application_Error处理程序中重定向的特殊情况。
答案 1 :(得分:150)
ASP.Net WebForms中的Redirect
问题有没有简单而优雅的解决方案。您可以选择 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
而不生成视图,就可以进行干净的重定向。
答案 2 :(得分:29)
我知道我已经迟到了,但如果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.
}
}
答案 3 :(得分:8)
Response.Redirect()
抛出异常以中止当前请求。
此KB article描述了此行为(也适用于Request.End()
和Server.Transfer()
方法)。
对于Response.Redirect()
,存在重载:
Response.Redirect(String url, bool endResponse)
如果传递 endResponse = false ,则不会抛出异常(但运行时将继续处理当前请求)。
如果 endResponse = true (或者如果使用了其他重载),则抛出异常并立即终止当前请求。
答案 4 :(得分:7)
这就是Response.Redirect(url,true)的工作原理。它抛出ThreadAbortException以中止线程。只是忽略那个例外。 (我认为它是一个全局错误处理程序/记录器,你在哪里看到它?)
答案 5 :(得分:6)
这是关于问题的official line(我找不到最新的,但我不认为.net的更高版本的情况已经改变了)
答案 6 :(得分:2)
此外,我尝试了其他解决方案,但重定向后执行了一些代码。
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
}
答案 7 :(得分:2)
我甚至试图避免这种情况,以防手动在线程上执行中止,但我宁愿将其留在" 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();
}
答案 8 :(得分:1)
我所做的是捕获此异常以及其他可能的异常。希望这有助于某人。
catch (ThreadAbortException ex1)
{
writeToLog(ex1.Message);
}
catch(Exception ex)
{
writeToLog(ex.Message);
}
答案 9 :(得分:0)
我也有这个问题。 尝试使用Server.Transfer而不是Response.Redirect 为我工作
答案 10 :(得分:-2)
我今天遇到了同样的问题。在我的项目中,我有两种类型的日志记录页面(简单用户和医生用户)。上周我完成了简单的用户日志记录页面,并且没有任何问题。本周我开始了医生登录页面。完成后,我再次检查了简单用户登录,发现它不起作用。我跟踪并意识到问题出在 response.redirect("simpleuser.aspx") (不要导航到 simpleuser.aspx)。 错误是(无法评估表达式,因为代码已优化或本机框架位于调用堆栈顶部。)我通过互联网检查了所有解决方案,没有运气......甚至“response.redirect(URL,false)” 我所做的,我只是将 simpleuser.aspx 复制到另一个目录....就是这样。完毕。 :)