我们有一个MVC.NET应用程序在重新启动时遇到致命错误。在我们的Session_Start事件处理程序中,我们将会话ID添加到字典中。在Session_End处理程序中,我们删除它。请考虑以下请求序列:
GET home.mvc
< application restarts>
获取main.css
GET banner.jpg
获取somedata.mvc
...
由于应用程序的架构方式,如果在浏览器窗口中打开应用程序时进行重建,则会发生此类序列。除了我在生产环境中看到它之外,这不会非常令人担忧。例如,编辑web.config时会发生(尽管很少)。
重启后的请求全部归因于主页中的链接或来自JavaScript的AJAX调用。
我观察到.NET并行处理前5个请求。每个这样的请求都会导致它触发Session_Start事件。片刻之后,它会激活Session_End事件3次。要清楚,每个Session_Start对应于完全相同的会话。它们都具有相同的会话ID,并且所有会话状态对象的IsNewSession属性都为true。此外,Session_End事件 not 对应于被杀死的会话。会话持续存在,以及存储在会话状态中的任何数据。
我需要阻止它多次触发Session_Start,或者弄清楚如何判断Session_End何时并不意味着会话已经结束。
答案 0 :(得分:3)
这个问题的答案结果相当直接,但行为当然令人困惑。
通常,MVC会将所有请求同步到应用程序的会话状态锁定上(因为MVC的http模块被标记为需要会话状态)。在我的方案中,应用程序在提供主页面后重新启动。因此,当与主页面相关的请求进入时,该会话ID还没有会话状态,并且请求并行执行。
我看到5个并行请求,因为我正在开发XP和桌面版本的IIS仅限于5个并发请求。由于任何这些请求都不存在会话状态对象,因此每个请求都会创建一个新的会话状态对象并触发Session_Start。其中四个请求转到MVC操作方法。由于这些需要会话状态,因此.NET会在请求完成后尝试将创建的会话状态对象与后备存储同步。
只有第一次同步才能成功。 .NET只丢弃三个额外的会话状态对象,并为每个对象触发Session_End。 .NET不会尝试将第五个会话状态对象与后备存储同步,因为它是为异步http模块创建的,该模块被标记为需要只读会话状态。
所以,修复有两个部分:
(1)在我的Session_Start处理程序中,我现在检查会话状态对象是否是只读的。如果是,那么我立即返回而不做任何事情。 .NET不会触发相应的Session_End,因此我所做的任何事情都不会被正确清理。
(2)我现在在字典中保留引用计数。每当Session_Start处理程序尝试添加会话ID并在每次Session_End尝试删除一个会话ID时递减计数,我都会递增计数。一旦计数达到0,我就从字典中删除会话ID。
答案 1 :(得分:1)
如果客户端向您发送已过期的值,则可以重用会话ID。阅读< sessionState> element的regenerateExpiredSessionId属性here并注意默认值为“true”
您可能还会发现this有趣:
答案 2 :(得分:0)
我在开发过程中遇到了一个旧的ASP.NET应用程序 - 事实证明,对于Cookie,RequireSSL设置为True ...这当然意味着会话cookie未被保留/重新发布客户端(localhost,非SSL) - 因此后续请求创建了新会话。