为什么我的ASP.NET MVC应用程序会在单个会话中多次触发Session_Start?

Pet*_*man 8 asp.net asp.net-mvc

我们有一个MVC.NET应用程序在重新启动时遇到致命错误.在我们的Session_Start事件处理程序中,我们将会话ID添加到字典中.在Session_End处理程序中,我们删除它.请考虑以下请求序列:

GET home.mvc
<application restarts>
GET main.css
GET banner.jpg
GET somedata.mvc
...

由于应用程序的架构方式,如果在浏览器窗口中打开应用程序时进行重建,则会发生此类序列.除了我在生产环境中看到它之外,这不会非常令人担忧.例如,编辑web.config时会发生(尽管很少).

重启后的请求都归因于主页中的链接或JavaScript的AJAX调用.

我观察到的是.NET并行处理前5个请求.每个这样的请求都会导致它触发Session_Start事件.片刻之后,它会激活Session_End事件3次.要清楚,每个Session_Start对应于完全相同的会话.它们都具有相同的会话ID,并且所有会话状态对象的IsNewSession属性都为true.此外,Session_End事件与被杀死的会话对应.会话持续存在,以及存储在会话状态中的任何数据.

我需要阻止它多次触发Session_Start或者弄清楚如何判断Session_End何时并不真正意味着会话已经结束.

Pet*_*man 4

这个问题的答案相当简单,尽管行为确实令人困惑。

通常,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。