为什么我的ASP.NET MVC应用程序为单个会话多次触发Session_Start? [英] Why does my ASP.NET MVC application fire Session_Start multiple times for a single session?

查看:214
本文介绍了为什么我的ASP.NET MVC应用程序为单个会话多次触发Session_Start?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We have an MVC.NET application that encounters fatal errors when it restarts. In our Session_Start event handler, we add the session id to a dictionary. In the Session_End handler, we remove it. Consider the following sequence of requests:

获取home.mvc
<应用程序重新启动>
获取main.css
GET banner.jpg
获取somedata.mvc
...

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

由于应用程序的构建方式,如果在浏览器窗口中打开应用程序时进行重建,则这种序列会经常发生.除了我也可以在生产环境中看到它之外,这并不是什么可怕的事情.例如,当您编辑web.config时,它将发生(尽管很少).

Because of the way the application is architected, this sort of sequence happens fairly frequently if you do a rebuild while the application is open in a browser window. That wouldn't be terribly concerning except that I see it in production environments too. For example, it will occur (albeit rarely) when you edit web.config.

重新启动后的请求全部归因于主页中的链接或来自JavaScript的AJAX调用.

The requests following the restart are all due to links in the home page or AJAX calls from JavaScript.

我观察到的是.NET并行处理前5个请求.每个此类请求都会导致其触发Session_Start事件.短时间后,它将触发Session_End事件3次.为了清楚起见,每个Session_Start都对应于完全相同的会话.它们都具有相同的会话ID,并且对于所有会话状态对象,IsNewSession属性为true.同样,Session_End事件 not 与被终止的会话相对应.该会话以及会话状态中存储的所有数据都会持续存在.

What I observe is that .NET handles the first 5 requests in parallel. Each such request causes it to fire the Session_Start event. After a short time, it fires the Session_End event 3 times. To be clear, each Session_Start corresponds to the exact same session. They all have the same session id and the IsNewSession property is true for all session state objects. Also, the Session_End events do not correspond to the session being killed. The session persists, along with any data stored in session state.

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

I need to either prevent it from firing Session_Start more than once or figure out how to tell when Session_End doesn't really mean that the session has ended.

推荐答案

这个问题的答案很直截了当,尽管这种行为肯定令人困惑.

The answer to this question turned out to be fairly straight-foward, though the behaviour was certainly confusing.

通常,MVC会将应用程序的会话状态锁上的所有请求同步到该应用程序(因为MVC的http模块被标记为需要会话状态).在我的情况下,应用程序在提供主页后重新启动.因此,当与主页相关的请求进入时,该会话ID尚无会话状态,并且这些请求并行执行.

Normally, MVC will synchronize all requests to an application on the application's session state lock (because MVC's http module is marked as requiring session state). In my scenario, the application restarts after serving the main page. Thus, when the main page-related requests come in, there is no session state for that session id yet and the requests execute in parallel.

我看到5个并行请求,因为我在XP上进行开发,而IIS的桌面版本仅限于5个并发请求.由于这些请求中的任何一个都不存在会话状态对象,因此每个请求都将创建一个新的会话状态对象并触发Session_Start.其中四个请求转到MVC操作方法.由于这些请求需要会话状态,因此一旦请求完成,.NET就会尝试将创建的会话状态对象与后备存储进行同步.

I see 5 parallel requests because I'm developing on XP and desktop versions of IIS are limited to 5 concurrent requests. Since the session state object does not exist for any of these requests, each request creates a new session state object and fires Session_Start. Four of the requests go to MVC action methods. Since these require session state, .NET tries to synchronize the created session state objects with the backing store once the requests complete.

只有第一次同步可以成功. .NET只是丢弃了三个额外的会话状态对象,并为每个对象触发了Session_End. .NET不会尝试将第五个会话状态对象与后备存储区同步,因为它是为异步http模块创建的,该异步http模块被标记为需要只读会话状态.

Only the first synchronization can succeed. .NET simply discards the three extra session state objects and fires Session_End for each one. .NET does not attempt to synchronize the fifth session state object with the backing store because it was created for an asynchronous http module which is marked as requiring readonly session state.

因此,修复程序分为两个部分:

So, the fix has two parts:

(1)现在,在我的Session_Start处理程序中,检查会话状态对象是否为只读.如果是这样,那么我什么也不做就立即返回. .NET不会触发相应的Session_End,因此我所做的任何事情都将无法正确清理.

(1) In my Session_Start handler, I now check if the session state object is readonly. If it is, then I return immediately without doing anything. .NET will not fire a corresponding Session_End, and thus anything I do won't be cleaned up properly anyway.

(2)现在,我在字典中保留引用计数.每当Session_Start处理程序尝试添加会话ID时,我都会增加计数,而每次Session_End尝试删除会话ID时,我都会减少计数.一旦计数达到0,我就从字典中删除会话ID.

(2) I now keep a reference count in my dictionary. I increment the count everytime a Session_Start handler tries to add a session id and decrement it everytime Session_End tries to remove one. Once the count reaches 0, I remove the session id from my dictionary.

这篇关于为什么我的ASP.NET MVC应用程序为单个会话多次触发Session_Start?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆