当我使用 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 调用 Redirect 重载,并调用以告诉 IIS 管道,一旦您返回控制,它应该直接进入 EndRequest 阶段:
Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();
Thomas Marquardt 的 This blog post 提供了更多详细信息,包括如何在 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 过滤器和模块,但它不会绕过当前 page 生命周期中的进一步事件。)
更深层次的问题是 WebForms 缺乏抽象层次。当您在事件处理程序中时,您已经在构建要输出的页面。在事件处理程序中重定向是丑陋的,因为您要终止部分生成的页面以生成不同的页面。 MVC 没有这个问题,因为控制流与渲染视图是分开的,因此您可以通过在控制器中简单地返回 RedirectAction
来执行干净的重定向,而无需生成视图。
Context
无法为您解决,请尝试 HttpContext
。
我知道我迟到了,但我只有在我的 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()
引发异常以中止当前请求。
此 KB article 描述了此行为(也适用于 Request.End()
和 Server.Transfer()
方法)。
对于 Response.Redirect()
,存在重载:
Response.Redirect(String url, bool endResponse)
如果传递 endResponse=false,则不会抛出异常(但运行时会继续处理当前请求)。
如果 endResponse=true (或者如果使用了其他重载),则抛出异常并立即终止当前请求。
这是有关问题的 official line(我找不到最新的,但我认为 .net 的更高版本的情况没有改变)
I think that links are fantastic, but they should never be the only piece of information in your answer.
这就是 Response.Redirect(url, true)
的工作原理。它抛出 ThreadAbortException
以中止线程。忽略那个例外。 (我认为它是您在哪里看到的一些全局错误处理程序/记录器?)
一个有趣的相关讨论Is Response.End()
Considered Harmful?。
我什至试图避免这种情况,以防万一手动在线程上执行中止,但我宁愿将它留在“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 class MyBasePage : Page
中的受保护方法
System.Web.UI.HttpContext
。真的System.Web.HttpContext
我也尝试了其他解决方案,但是重定向后执行了一些代码。
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
为我工作。
不定期副业成功案例分享
Context.ApplicationInstance.CompleteRequest();
之后执行代码。为什么?我必须有条件地从事件处理程序中return
吗?The old version of Redirect
短语更准确,这不像 MS 改变了实现,它只是另一个重载。