Replacing ASP.Net’s session entirely

asp.netconcurrencysessionsession-state

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:

  1. Locking read & write (default) – the session is locked from AcquireRequestState firing until ReleaseRequestState 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…

  2. 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.

  3. 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.

Best Answer

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.