完全替换 ASP.Net 的会话
ASP.Net 会话对于传统的 WebForms 应用程序来说似乎很完美,但它们所做的一些事情对于现代 AJAX 和 MVC 应用程序来说是一个严重的问题。
具体来说,只有 3 种方法可以访问 ASP.Net 提供程序:
锁定读取和锁定。 write(默认)- 会话从
AcquireRequestState
触发一直锁定到ReleaseRequestState
触发。如果浏览器同时发出 3 个请求,它们将在服务器上排队。这是 MVC 2 中唯一的选项,但 MVC 3 允许...非锁定只读 - 会话未锁定,但无法保存。这似乎不可靠,因为某些读取似乎会再次锁定会话。
会话已禁用 - 任何读取或写入会话的尝试都会引发异常。
然而,对于现代 MVC 应用程序,我会同时发生大量 AJAX 事件 - 我不希望它们在服务器上排队,但我确实希望它们能够写入会话。
我想要的是第四种模式:脏读,最后写入获胜
我认为(很高兴得到纠正)做到这一点的唯一方法是完全替换 ASP.Net 的会话。我可以编写我的自己的提供程序,但 ASP 仍会用一个来调用它它支持的 3 种模式。有没有办法让ASP.Net支持乐观并发?
这让我用一个新类替换了对会话的所有调用,该类基本上执行相同的操作,但不锁定 - 这是一个痛苦。
我希望以最少的代码替换量保留尽可能多的当前会话内容(最重要的是各种日志中的会话 ID)。有什么办法可以做到这一点吗?理想情况下,我希望 HttpContext.Current.Session 指向我的新类,但 ASP.Net 不会锁定任何请求。
有人已经做过这样的事情了吗?奇怪的是,对于所有 AJAXey MVC 应用程序来说,这是 ASP 的一个新问题。
ASP.Net session appear perfect for a traditional WebForms app, but they do some things that are a serious problem for a modern AJAX and MVC application.
Specifically there are only 3 ways to access the ASP.Net provider:
Locking read & write (default) - the session is locked from
AcquireRequestState
firing untilReleaseRequestState
fires. If 3 requests occur from the browser at once they'll queue up on the server. This is the only option in MVC 2, but MVC 3 allows...Non-locking read only - the session isn't locked, but can't be saved to. This appears to be unreliable though, as some reads appear to lock the session again.
Session disabled - any attempt to read or write to the session throws an exception.
However with a modern MVC app I have lots of AJAX events happening at once - I don't want them the queue on the server but I do want them to be able to write to the session.
What I want is a fourth mode: Dirty read, last write wins
I think (happy to be corrected) that the only way to do this is to completely replace ASP.Net's sessions. I can write my own provider, but ASP will still call it with one of the 3 patters it supports. Is there any way to make ASP.Net support optimistic concurrency?
This leaves me replacing all calls to the session with a new class that basically does the same thing, but doesn't lock - which is a pain.
I want to keep as much of the current session stuff as I can (most significantly session IDs in various logs) with the minimum amount of code replacement. Is there any way to do this? Ideally I'd want HttpContext.Current.Session
to point to my new class but without ASP.Net locking any requests.
Has anyone already done something like this? It seems odd that with all the AJAXey MVC apps out there this is a new problem with ASP.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先我说 MS asp.net 锁定了“asp.net 处理页面”会话的核心,位于 asp.net 4 的“webengine4.dll”dll
中从 MS
asp.net 的角度说,以这种方式正确操作并锁定会话
因为 asp.net 无法知道我们在会话中保留什么类型的信息,所以可以做出正确的“最后写入获胜” ”。正确的方法是锁定会话整个页面,因为这种方式为您的程序提供了非常重要的同步,根据现在的经验,我说您在大多数情况下都需要它你的行动。在我用我的会话替换 ms 会话后,我需要对所有操作进行全局锁定,否则我会遇到双重插入、双重操作等问题。
我给出了该问题的示例我在这里认识的。会话数据保存在 SessionSateItemCollection 中,它是一个键列表。当会话读取或写入此集合时,所有这些操作都会一起完成。那么我们来看看这个案例吧。
我们在会话中有树变量“VAR1”、“VAR2”、“VAR3”
第 1 页。
getsession(实际上获取所有数据并将它们放在列表中)
会话[VAR1] = "数据1";
保存会话()
结果为 VAR1=data1,VAR2=(var2 的最后一个数据),VAR3=(var3 的最后一个数据)
第 2 页。
getsession(实际上获取所有数据并将它们放在列表中)
会话[VAR2] = "data2";
保存会话()
结果为 VAR1=(var1 的最后一个数据)、VAR2=data2、VAR3=(var3 的最后一个数据)
第 3 页。
getsession(实际上获取所有数据并将它们放在列表中)
会话[VAR3] = "data3";
保存会话()
结果是 VAR1=(var1 的最后一个数据), VAR2=(var2 的最后一个数据) VAR3="data3"
请注意,每个页面都有数据的克隆,因为他从会话介质中读取它们(例如,最后读取的数据) 如果我们让这 3 个页面在没有锁定的情况下运行,我们实际上不会发生脏读,
也不会出现“最后写入获胜” - 我们这里拥有的是“最后写入破坏了其他页面”,因为如果你这么认为再说一次,当VAR1改变时,为什么VAR2和VAR3保持不变?如果你在其他地方改变了VAR2怎么办?
出于这个原因,我们不能让这件事不加锁。
现在用 20 个变量来想象……完全混乱。
可能的解决方案
由于 asp.net 的多个池是多线程的,跨池和跨计算机保持相同数据的唯一方法是拥有一个公共数据库,或者像 asp.net State Service 这样的所有进程程序共用的数据库。
我选择拥有一个通用数据库,因为它比为此建议创建一个程序更容易。
现在,如果我们将我们制作的cookie连接到会话的数据用户,并且我们使用我们知道的完全自定义的数据库字段来控制数据我们喜欢锁定,不是什么,如何保存或更改,或者比较并保留最后写入的获胜数据,我们可以使这项工作正常进行,并完全禁用 asp.net 会话,这是为所有需求而设计的通用会话保持器,但是不是为了处理像这样的特殊情况而设计的。
asp.net 可以在未来的版本中实现此功能吗?是的,他可以通过创建一个名为脏的额外字段,并在会话上保存数据,使用脏字段或类似的方式合并数据,但不能这样做现在按原样工作 - 至少从我到目前为止所发现的情况来看是这样。
实际上 SessionStateItem 在属性上有一个脏标志,但没有在保存数据结束时进行合并。如果有人想找到现有的 ms asp.net 会话状态管理器的解决方案,我真的很高兴,我正在写我到目前为止所发现的内容,但这并不意味着肯定没有办法 - 我还没有发现它就是这样。
希望大家有所帮助:)
此答案中的自定义SessionStateModule
https://stackoverflow.com/a/3660837/159270 James编写自定义模块后说:我仍然不敢相信 ASP.Net Session 的自定义实现会锁定整个请求的会话。
First of all I say that MS asp.net have lock in the core of "asp.net processing a page" the session, somewhere in the "webengine4.dll" dll for asp.net 4
And I say that from the view point of MS
asp.net act correct and lock the session this way
because asp.net can not know what type of information we keep on session so can make a correct "last write wins".Also correct is lock for the session the full page because that way is gives your a very important synchronizations of your program, that from experience now I say you need it for most of your actions. After I have replace the ms session with mine, on all of my actions I need to make global lock, or else I have problems with double inserts, double actions, etc.
I give an example of the issue that I recognize here. Session data are saved on SessionSateItemCollection that is a list of keys. When session reads or write this collection is do it all of them together. So let see this case.
we have tree variables on session, "VAR1", "VAR2", "VAR3"
Page 1.
getsession (actually get all data and place them on list)
session[VAR1] = "data1";
savesession()
result is VAR1=data1, VAR2=(last data of var2), VAR3=(last data of var3)
Page 2.
getsession (actually get all data and place them on list)
session[VAR2] = "data2";
savesession()
result is VAR1=(last data of var1), VAR2=data2, VAR3=(last data of var3)
Page 3.
getsession (actually get all data and place them on list)
session[VAR3] = "data3";
savesession()
result is VAR1=(last data of var1), VAR2=(last data of var2) VAR3="data3"
Note here that each page have a clone of the data, as he read them from the session medium (eg as they last readed from database)
If we let this 3 pages run with out locking, we do not have actually dirty read, nether "last write wins" - What we have here is "the last write destroy the others", because if you think it again, when VAR1 change, why the VAR2 and VAR3 stay the same ? what if you have change VAR2 somewhere else.
and for that reason we can not let this with out lock as it is.
And now imaging that with 20 variables... totally mess.
Possible solutions
Because of the multithread of asp.net of many pools, the only way to keep the same data across pools, and across computers is to have a common database, or a common to all process program like the asp.net State Service.
I select to have a common database as more easy than create a program for that propose.
Now if we connect a cookie that we make, to the user to the data user of the session, and we control the data using a totally custom database field that we know what we like to lock, what not, how to save or change, or compare and keep the last write wins data, we can make this work, and totally disable the asp.net session that is a generic session keeper made for all needs, but not made to handle special cases like this one.
Can asp.net make this work on the future release, yes he can by making an extra field called dirty, and on the session save data, make a merge of data using the dirty field, or something like that, but can not make this now work as it is - at least from what I have found until now.
Actually SessionStateItem have a dirty flag on properties, but did not make this merge on the end of save data. I will really love if some one else think for a solution to the existing ms asp.net session state keeper, I am write what I have found up to now, but this is not mean that for sure there is no way - I have not found it as it is.
Hope that all helps :)
Custom SessionStateModule
in this answer https://stackoverflow.com/a/3660837/159270 the James after write a custom module says: I still can't believe the custom implementation of ASP.Net Session locks the session for the whole request.