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






4.50/5 (4投票s)
您应该了解有关会话开始/结束事件的信息,以便保护您的应用程序免受可能的性能问题的影响。
这个问题
在浏览 StackOverflow 时,我偶然发现了一个来自 2 月 10 日的旧的未解答的问题,引起了我的注意。
起初,我很快将其视为无稽之谈,但后来我开始进一步研究并产生了兴趣。 似乎很多人都在报告一个问题,即Session_End
有时会在Session_Start
之后立即被调用。
这可以在 .NET 2.0/3.5 中通过以下步骤重现
- 创建一个新的 .NET 2.0 WebForms WebApplication
- 配置 InProc 的会话,并将超时设置为 1 分钟
- 在
Session_Start
和Session_End
事件上添加断点 - 调试应用程序并按 F5 跳过第一个
Session_Start
断点 - 等待 1 分钟后
Session_End
触发 - 刷新浏览器,并注意
Session_End
在Session_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 并且有昂贵的代码挂钩到会话开始/结束事件中,那么我建议您向会话开始例程添加一个虚拟会话变量。 这通过将会话标记为正在使用来解决问题,并有助于保护您的服务器资源免受过多的会话事件的影响。