65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 会话结束事件在会话开始后立即触发 - 已解决

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (4投票s)

2011 年 8 月 27 日

CPOL

2分钟阅读

viewsIcon

66990

您应该了解有关会话开始/结束事件的信息,以便保护您的应用程序免受可能的性能问题的影响。

这个问题

在浏览 StackOverflow 时,我偶然发现了一个来自 2 月 10 日的旧的未解答的问题,引起了我的注意。

起初,我很快将其视为无稽之谈,但后来我开始进一步研究并产生了兴趣。 似乎很多人都在报告一个问题,即Session_End有时会在Session_Start之后立即被调用。

这可以在 .NET 2.0/3.5 中通过以下步骤重现

  • 创建一个新的 .NET 2.0 WebForms WebApplication
  • 配置 InProc 的会话,并将超时设置为 1 分钟
  • Session_StartSession_End事件上添加断点
  • 调试应用程序并按 F5 跳过第一个Session_Start断点
  • 等待 1 分钟后Session_End触发
  • 刷新浏览器,并注意Session_EndSession_Start之后立即被调用
  • 请注意,将一个会话变量添加到页面OnLoad解决了这个问题

根据文档,有 2 种活动会导致Session_End事件触发。

  • Session.Abandon()被调用时
  • Session过期后立即

在这个例子中,没有一个是true。 那么这怎么可能呢?

答案

在互联网上做了一些研究,我在一篇关于会话状态的博客文章中发现了一条线索。 它揭示了关于如何处理会话状态的一个有趣的怪癖。

这就是 ASP.NET 只有在应用程序实际使用会话时才会创建一个新的InProc会话。 如果没有,则会话不会被持久化,甚至不会发出会话 cookie(如果它还不存在)。

所以这就是发生的事情。

当浏览器在会话超时后刷新时,旧的会话 cookie 会在请求中发送。 这会导致 ASP.NET 为新会话重用原始会话 ID。 但是,因为在请求结束时,应用程序尚未使用的会话,ASP.NET 有效地放弃它以避免持久化并释放资源。 这导致了早期的Session_End事件。

现在,由于 ASP.NET 实际上没有删除预先存在的会话 cookie,因此每个后续请求本质上都是重新启动会话 ID 并重复事件序列,因此会重复触发Session_Start/Session_End,直到会话被使用或 cookie 被删除。

修复方案

该问题已经在 .NET 4.0 中得到解决。 我怀疑在会话重新启动的情况下,会话现在仍然保持持久化。

如果您的应用程序使用 .NET 2.0/3.5 并且有昂贵的代码挂钩到会话开始/结束事件中,那么我建议您向会话开始例程添加一个虚拟会话变量。 这通过将会话标记为正在使用来解决问题,并有助于保护您的服务器资源免受过多的会话事件的影响。

© . All rights reserved.