【问题标题】:In ASP.Net, How do I run code after sending page在 ASP.Net 中,我如何在发送页面后运行代码
【发布时间】:2010-08-25 18:43:14
【问题描述】:

在 ASP.Net 中,我想在页面已经发送给用户之后运行一些代码(日志记录、其他清理)。我不希望此代码干扰客户端接收响应所需的时间。我尝试将此代码放在页面的 OnUnload 部分,但通过测试(使用断点或繁忙的等待循环),客户端实际上不会显示页面,直到 OnUnload 中的代码完成执行。即使此时响应对象不再可用,因此我假设缓冲的响应已发送到客户端,但客户端仍然不会显示页面,直到 OnUnload 完成执行。目前似乎可行的唯一方法是启动一个新线程来完成这项工作,并让 OnUnload 立即完成。但是,我不知道这是否安全。如果在页面发出后执行时间过长,服务器会杀死线程吗?有没有更正确的方法来做到这一点?

【问题讨论】:

  • 您可以使用消息队列并让后台进程处理它吗?更像是 Web 角色和辅助角色应该如何在 Azure 中相互交互?
  • 我试图帮助投票,但看起来有人真的不喜欢这个问题!
  • 如果问题太久没有回复,我通常会删除它们。通常你以后不会得到一个,它有助于限制来自 SO 的未回答(并且基本上无用)的问题的数量。
  • 什么类型的清理?异步页面会有帮助吗? msdn.microsoft.com/en-us/magazine/cc163725.aspx#S2

标签: asp.net page-lifecycle


【解决方案1】:

基比,

尝试重写 Page.Render 方法并像这样刷新响应:

Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
    MyBase.Render(writer)

    Response.Flush() ' Sends all buffered output to the client

    ' Run some code after user gets their content
End Sub

我认为此时响应仍未完成,但用户将在您完成运行最终代码之前获得页面呈现的内容。

HTH,

迈克

【讨论】:

  • 这按预期工作。有了可用的 Repsonse 对象,我就可以让浏览器接收和呈现内容。然而问题是浏览器页面仍然显示为加载(旋转图标/沙漏),类似于页面加载时,即使在接收到内容之后也是如此。即使在 Response.Flush() 之后添加了 Response.Close,这种行为仍然存在。也很高兴看到其他人在 VB.Net 中编码。似乎这里的大部分 .Net 东西都集中在 C# 上。
  • 我很确定响应不会完全关闭,直到整个 ASP.net 生命周期完成执行。这包括 AFIAK 是生命周期中绝对最后一点的 HttpApplication.EndRequest 事件(当然不包括应用程序结束的时间)。我认为上述方法将最接近您想要的,而不会产生新线程。如果您使用多线程,那么我建议在 HttpApplication.EndRequest 中生成线程以避免线程在 Response.End() 上中止。
【解决方案2】:

卸载是 ASP.NET 页面生命周期的最后一部分。见以下链接:

http://msdn.microsoft.com/en-us/library/ms178472.aspx

这是你可以用 javascript 或 AJAX 做的事情吗?

【讨论】:

  • 我特别声明我尝试使用卸载部分,但在卸载代码完成之前浏览器仍然不显示页面。这不是我在 Javascript 或 Ajax 中可以做的事情,因为它必须在服务器端运行,而且我不能依赖启用了 Javascript 的客户端来进行 AJAX 调用来启动进程。
  • Kibbee 我读到了,但你没有说你知道这是页面生命周期的最后一个阶段,这就是我提到它的原因。我认为它不值得-1,但如果您要叮嘱我试图帮助您了解 asp.net 的工作原理,我肯定不会在将来发布您的任何问题。
  • 对不起,但我觉得“这个答案没用”的反对意见的描述真的适用于这里。就个人而言,我发现如果您实际上没有提供可以解决问题的信息,您应该将其作为评论留下。您给出的答案只是额外的信息。它根本无法解决我遇到的问题。
【解决方案3】:

挂钩到 page.Disposed 事件而不是 Unload 事件怎么样?

【讨论】:

  • 试过了。看起来在代码执行之前发送页面时,我现在面临的问题是代码似乎根本没有运行。尽管它可能会在将来某个时候运行,当对象本身被处置时。我希望代码以更及时的方式执行,而不是在处理对象时。
【解决方案4】:

根据您需要执行的操作,可以创建 ISAPI 过滤器以在响应结束时执行操作。

【讨论】:

    【解决方案5】:

    你可以试试这个解决方案 - Best ASP.NET Background Service Implementation

    使用 Windows 服务并通过 MSMQ 与其通信可能是一种更可靠的解决方案,并且可以更好地扩展。这将帮助您分离关注点,让 asp.net 前端只关注用户,而 Windows 服务专注于后台任务。

    如果您要使用 azure 迁移到云,您可以简单地将 asp.net 前端替换为 web 角色,并将 windows 服务替换为 worker 角色,您的解决方案可以无缝扩展!

    【讨论】:

      【解决方案6】:

      这是一种乡巴佬的做法。有第二个 aspx 页面来执行所有“清理”后渲染逻辑。例如,称其为“cleanup.aspx”。让您的清理代码在 cleanup.aspx 的 Page_Load 中运行:

      public partial class cleanup: System.Web.UI.Page
      {
          protected void Page_Load(object sender, EventArgs e) 
          {
              // do logging blah blah here....
          }
      }
      

      在您的主 aspx 页面中,有一个 JavaScript 函数,该函数对“cleanup.aspx”进行 AJAX 调用。在页面加载后触发 AJAX 函数。我推荐 jquery,如果是这样,您的代码将如下所示:

      $(function(){
          yourAJAXYFunctionName();
      });
      
      function yourAJAXYFunctionName()() {
       // ajax code here
       //  
       $.ajax({
         url: "cleanup.aspx",
        });
      }
      

      这样,您的第一个页面的代码运行,然后页面被发送到浏览器。当页面呈现给客户端时,第二个 ASPX 页面通过 AJAX 调用,这与 cleanup.aspx 无关,它不关心它是如何调用的以及它的页面加载事件是如何执行的。然后运行您的清理/日志记录代码。

      注意事项:客户端 JavaScript 是必需的。但是,到底谁没有运行 JS 呢?此外,您的 cleanup.aspx 页面完全从您的主页中抽象出来,因此如果您想使用 cleanup.aspx 中源自您的第一页的任何对象,那么您必须将它们存储在会话或 cookie 中,或者您可以在 AJAX 调用中将它们作为参数传递。这将需要对 AJAX 脚本本身进行动态操作,但这并不难。

      【讨论】:

        【解决方案7】:

        我想试试 try{Response.End()}catch{} runco​​de();

        【讨论】:

        • 在当前状态下,这并不是真正的答案。请重新格式化。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-23
        • 1970-01-01
        相关资源
        最近更新 更多