Replacing default ASP.NET (2.0) SessionStateStoreProvider.
Abstract:
One of the good things that ASP.NET brings along is the Provider model that let us replace default ASP.NET providers with our own providers. The "provider" model let us changes several Session providers such as SessionIDModule and storage provider. Although HttpSessionStateProvider implement interface called IHttpSessionState I didn’t find any way in the code or any sign that it might be changed by config settings. I just found uses of HttpSessionStateProvider and no sign for using IHttpSessionState and loading implement class from config file. Since I'm a fan of the session mechanism I decide to wear my madness suit and to try to create my own session store provider that uses memory map file (MMF) as session storage. Those lines describe the work that I've been done by now. And yes, I've also attached sample demo to those lines (the demo is just to demonstrate session store replacement I didn’t take the effort of optimize my solution).
Phase 1: who's in that game?
First of all I want to know which classes are playing in that game, who calls who, when and what they pass. The natural place to start with is documentations or publications, but due to the early stage of that version I didn’t found any document that explains those details. So naturally I activate Lutz .Net Reflector to learn about the new session.
It all starts with SessionStateModule which implement the IHttpModule and get called by the application; actually the application calls Init method of SessionStateModule. Init method calls InitModuleFromConfig that set internal member of SessionStateStoreProviderBase type by the application configuration settings. If configuration settings set to custom provider InitCustomStore method is being called and return instance of the defined class as declared in application config file.
While the application initializes SessionStateModule the following methode of your implementation of SessionStateStoreProviderBase will be called:
- Your class constructor: As part of the initialization of modules your class constructor will be called first.
- Initialize: the Initialize method (of System.Configuration.Provider.ProviderBase that SessionStateStoreProviderBase derived from) is the second method to be call. Use it to set your provider name and call the base implementation.
- SetItemExpireCallback: The last method that called in the initialize phase let you register callback function that will be called when session item will expire.
- BeginRequest: is the first method called by SessionStateModule every attempt to get/set session data. Typically used for initialization of internal state.
- CreateNewStoreData: create new instance of sessionStateStoreData, which holds the session item, static items and session timeout.
Every call after Session initialization will call the following methods:
- BeginRequest: See above.
- GetItemExlusive: Get the stored SessionStateStoreData from the persistence medium.
Every call when session state released by the application (OnReleaseState called by application SyncExecuteStep) the following methods is being called:
- SetAndReleaseItemExculsive: save SessionStateStoreData to custom persistence medium.
- EndRequest: called when the request ended.
When needed the rest of the following implemented methods will be called:
- CreateUninitializedItem: create new instance of SessionStateStoreData and save it into custom persist medium. CreateUninitializedItem get called by SessionStateModule if config file indicate to regenerate expired session ID.
- Dispose: get called by SessionStateModule Dispose method. Used to release objects, if needed.
- GetItem: called by SessionStateModule when the request for the session is read only. Perform the same functionality of GetItemExlusive without locking.
- ReleaseItemExlusive: release SessionStateStoreData if timeout exceeded or as part of SessionStateModule OnReleaseState method.
- RemoveItem: remove SessionStateData. Called as part of SessionStateModule OnReleaseState method.
- ResetItemTimeout: called every time SessionStateModule End event added or removed.
-
Phase 2: what should I need to change?
1) Create my own class that inherits from SessionStateStoreProviderBase. As you see in phase 1, session module calls any type of session storage provider as long as it implements SessionStateStoreProviderBase.
2) Don’t forget to implement Initialize (member of System.Configuration.Provider.ProviderBase that SessionStateStoreProviderBase derived from)
3) Change the following settings in your web.config file:
<sessionState mode ="Custom" customProvider ="NattyProvider">
<providers >
<add name ="NattyProvider" type ="NattySessionSupplier.NattySessionStore, NattySessionSupplier"/>
</providers>
</sessionState>
Phase 3: writing the code:
I started with big ambitions, I want to change the default SessionStateStoreData and store it in custom persistence medium – MMF. I use my article (http://www.thecodeproject/dotnet/globalcache.asp ) as persist medium, and thought I just need to serialize/deserialize my custom SessionStateStoreData to MMF files and I'm done.
Pretty fast I learned that ASP.NET hides very effectively the implementation of serialize/deserialize state Session items and static items. Actually the only way that I found to serialize/deserialize those items is by using SessionStateUtility, SerializeStoreData and Deserialize methods. The problem was that those methods are internals, so I kind of implemented them in my own class, which inherits from SessionStateStoreProviderBase.
I named my class that derived from SessionStateStoreProviderBase as NattySessionStore. Except for implementation of SessionStateStoreProviderBase methods, that I'll deal with later, I implement SerializeStoreData and Deserialize methods. SerializeStoreData demand implementation of Serialization so I created it as well. You can look at the code, but basically those functions use SessionStateItemCollection and HttpStaticObjectCollection Serialization and Deserialization methods.
Another method of SessionStateUtility that I need to rewrite is CreateLegitStoreItem. CreateLegitStoreItem simply create new instance of SessionStateStoreData. I'll discuss later who call that method.
All other methods (except DoGet) are implementation of SessionStateStoreProviderBase decleration. Here are main issues regarding the implementation:
General notes:
- Most of the methods are using internal static method of SessionIDModule – CheckIdLength. Because this method signs as internal you can't access it. You can create your own SessionIDModule (by implementing ISessionIDModule) and expose such
- Most of the methods are calling internal method called CreateSessionStateCacheKey. This method supposes to return unique value to identify the session. I simply add "nat" to the session id.
- I didn’t address the locking mechanism of updating session data.
Specific notes:
- BeginRequest: Empty.
- CreateNewStoreData: creation of SessionStateStoreData.
- CreateUninitializeItem: create SessionStateStoreData by calling CreateNewStoreData. Serialize the item into custom persist medium.
- Dispose: Empty.
- EndRequest: Empty.
- DoGet: private method. Use Deserialization to create SessionStateStoreData from persist medium.
- GetItem / GetItemExcusive : call DoGet method (no lock, with locking)
- Initialize: just add Name if the method being called with null name parameter.
- ReleaseItemExlusive: I just use it to remove item from persist medium.
- RemoveItem: Same as ReleaseItemExlusive, although ReleaseItemExlusive should be different if exclusive get was implemented.
- ResetItemTimeout: Empty. Should be used to update the DateTime stamp of the item in the cache.
- SetAndReleaseItemExclusive: use SerializeStoreData to convert SessionStateStoreData into byte array and then store it in persist medium.
- SetItemExpireCallback: set an event that will be called when item expired.
Get the custom session storage sample HERE