【问题标题】:C# ASP.NET Events still fire after calling Context.ApplicationInstance.CompleteRequest (Response.Redirect related)C# ASP.NET 事件在调用 Context.ApplicationInstance.CompleteRequest 后仍然触发(与 Response.Redirect 相关)
【发布时间】:2018-01-25 17:17:48
【问题描述】:

尝试遵循 Response.Redirect 的最佳实践

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

如本 MSDN 博客所述:correct-use-of-system-web-httpresponse-redirect 这基本上是说:

使用不会导致线程中止的 CompleteRequest 重载 例外。

CompleteRequest 的 MSDN 页面说:

导致 ASP.NET 绕过 HTTP 管道中的所有事件和过滤 执行链,直接执行 EndRequest 事件。

但是,调用 CompleteRequest 后的所有页面事件仍然会触发。所以没有代码被跳过。这似乎与 MSDN 文档相矛盾。有解决方法吗?我误解了文档吗?

博客文章确实说跳过是在页面级别,但 API 文档没有这么说。我猜答案只是文档具有误导性。

您可以通过调试步进来测试一个相当简单的页面:

<asp:CheckBox ID="CheckBox0" runat="server" OnCheckedChanged="chk_CheckedChanged" />
<asp:CheckBox ID="CheckBox1" runat="server" OnCheckedChanged="chk_CheckedChanged" />
<asp:CheckBox ID="CheckBox2" runat="server" OnCheckedChanged="chk_CheckedChanged" />
<asp:CheckBox ID="CheckBox3" runat="server" OnCheckedChanged="chk_CheckedChanged" />
<asp:Button ID="btnRedirect" runat="server" Text="Click Me" OnClick="btnRedirect_Click" />
<asp:Label ID="lblNotes" runat="server" />

代码:

protected void Page_Load(object sender, EventArgs e)
{
    lblNotes.Text += " Load " + DateTime.Now.ToString();
}

protected void Page_PreRender(object sender, EventArgs e)
{
    lblNotes.Text += " PreRender " + DateTime.Now.ToString();
}

protected void chk_CheckedChanged(object sender, EventArgs e)
{
    Response.Redirect("stackoverflow.com", false);
    Context.ApplicationInstance.CompleteRequest();
}

protected void btnRedirect_Click(object sender, EventArgs e)
{
    lblNotes.Text += " Btn " + DateTime.Now.ToString();
}

如果您选中所有复选框,然后按下按钮会触发许多事件。

【问题讨论】:

  • 通过在 Response.Redirect 中使用 false 来结束当前线程的进一步执行。所以在某些情况下可能会导致问题。
  • @Ravikumar 我认为反过来。在 Response.Redirect 中使用 True 会结束当前线程的进一步执行,这会引发 ThreadAbort 异常。这是我试图避免的。这就是为什么我传错了。
  • 你能分享更多代码或你的完整执行线程吗?

标签: c# asp.net redirect exception


【解决方案1】:

您似乎在想 CompleteRequest() 方法会终止页面的执行,类似于 Response.Redirect(url, true)。但是,正如 John S Reid 在this article 中所解释的那样,CompleteRequest 只会结束在 ASP.NET 应用程序生命周期中的页面执行步骤之后发生的应用程序事件,这可能会根据 ASP.NET 的版本而有所不同。

页面仍然会处理回发事件并呈现页面,但如果您对示例感兴趣,上面的文章有一个示例,说明如何防止这种情况发生。

以下是您的示例代码可能的样子:

private m_bIsTerminating = false;

protected void chk_CheckedChanged(object sender, EventArgs e)
{
    Response.Redirect("Default2.aspx", false);
    Context.ApplicationInstance.CompleteRequest();
    m_bIsTerminating = true;
}

protected void btnRedirect_Click(object sender, EventArgs e)
{
    lblNotes.Text = "button click event";
}

protected override void RaisePostBackEvent(IPostBackEventHandler 
    sourceControl, string eventArgument)
{
    if (m_bIsTerminating == false)
    base.RaisePostBackEvent(sourceControl, eventArgument);
}

protected override void Render(HtmlTextWriter writer)
{
    if (m_bIsTerminating == false)
    base.Render(writer);
}

如果您在选中复选框并单击按钮后进行调试,复选框将引发一个回发事件,然后是一个渲染,这两个事件都不会被调用。那么按钮点击事件将不会被处理并发生重定向。

另外,我发现了这个stackoverflow post,它与这个问题类似,并介绍了与 CompleteRequest() 方法有关的更多信息。

【讨论】:

  • 没想到它会终止执行我只是希望在调用 CompleteRequest 后未处理的回发事件不会触发,因为这就是 MSDN 文档所暗示的情况。我的问题是行为与文档不符。
  • 那篇文章确实提供了一种使用覆盖 RaisePostBackEvent 和 Render 的解决方法。请发布答案,包括该部分内容和原始文章的链接。然后我会将其标记为已接受的答案。
  • “John S Reid”解决方法涵盖在 Page_Load 内引发重定向的情况。不幸的是,如果重定向是在回发事件中完成的,它不会阻止所有其他事件的触发。
  • 我添加了一个示例,说明如何在 checkchanged 事件中覆盖回发事件/渲染。希望这能让您了解如何在 Page_Load 之外的其他地方进行操作。另外,那是 John S. Reid 的公司网站,所以应该是原始文章。
猜你喜欢
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
相关资源
最近更新 更多