I implemented a Custom Session State Module and added to the application as follows (web.config):
<system.webServer>
<modules>
<remove name="Session" />
<add name="Session" type="CustomServerModules.StateServer.SessionState.SessionStateModule" preCondition="managedHandler" />
</modules>
</system.webServer>
My IIS Application Pool is set to Integrated v4.0
I added SessionStateData (exactly HttpSessionStateContainer
object) to the HttpContext
on BeginAcquireState
event (according to Microsoft's SessionStateModule):
SessionStateUtility.AddHttpSessionStateToContext(_rqContext, _rqSessionState);
But my problem is Session
Object in Page
has no value and it throws exception:
Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the <configuration>\\<system.web>\\<httpModules> section in the application configuration.
Also HttpContext.Current.Session
is null.
Now the question is: Why is the Session not accessible in application pages in this custom mode? How can I trace the behavior of IIS and ASP.NET when creating and initiating HttpApplications and Page instances to trace the Session object?
UPDATE
I included the AcquireRequest Way of my Session HttpModule as follows. in this section the new Session will add to the HttpContext
and Session_Start
will raise:
public sealed class SessionStateModule : IHttpModule
{
/*
* Add a Session_OnStart event handler.
*/
public event EventHandler Start
{
add
{
_sessionStartEventHandler += value;
}
remove
{
_sessionStartEventHandler -= value;
}
}
/*
* IHttpModule Member
*/
public void Init(HttpApplication app)
{
bool initModuleCalled = false;
string applicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;
var webConfig = WebConfigurationManager.OpenWebConfiguration(applicationName);
s_sessionWebConfig = (SessionStateSection)webConfig.GetSection("system.web/sessionState");
lck = new ReaderWriterLockSlim();
if (!s_oneTimeInit)
{
lck.EnterWriteLock();
try
{
if (!s_oneTimeInit)
{
initializeModuleFromWebConfig(app);
initModuleCalled = true;
s_Application = app;
s_timeOut = (int)s_sessionWebConfig.Timeout.TotalMinutes;
s_useHostingIdentity = s_sessionWebConfig.UseHostingIdentity; // default value of UseHostingIdentity is true.
s_configExecutionTimeout = ((HttpRuntimeSection)webConfig.GetSection("system.web/httpRuntime")).ExecutionTimeout; // DefaultValue of ExecutionTimeout = "00:01:50"
s_configRegenerateExpiredSessionId = s_sessionWebConfig.RegenerateExpiredSessionId;
s_configCookieless = s_sessionWebConfig.Cookieless;
s_configMode = s_sessionWebConfig.Mode;
// The last thing to set in this if-block.
s_oneTimeInit = true;
}
}
finally
{
lck.ExitWriteLock();
}
}
if (!initModuleCalled)
{
initializeModuleFromWebConfig(app);
}
}
private void initializeModuleFromWebConfig(HttpApplication app)
{
#region registering application (HttpApplication) event handlers
app.AddOnAcquireRequestStateAsync(
new BeginEventHandler(this.app_BeginAcquireState),
new EndEventHandler(this.app_EndAcquireState));
app.ReleaseRequestState += app_ReleaseRequestState;
app.EndRequest += app_EndRequest;
#endregion
#region instantiating SessionStateStoreProvider
string providerName = s_sessionWebConfig.CustomProvider;
ProviderSettings ps;
_store = (SessionStateStoreProviderBase)
ProvidersHelper.InstantiateProvider(ps, typeof(SessionStateStoreProviderBase));
#endregion
_idManager = initSessionIDManager(s_sessionWebConfig);
}
private IAsyncResult app_BeginAcquireState(object source, EventArgs e, AsyncCallback cb, object extraData)
{
bool requiresState;
bool isCompleted = true;
bool skipReadingId = false;
_acquireCalled = true;
_releaseCalled = false;
resetPerRequestFields();
_rqContext = ((HttpApplication)source).Context;
_rqAr = new HttpAsyncResult(cb, extraData);
try
{
/* notifying the store that we are beginning to get process request */
_store.InitializeRequest(_rqContext);
/* determine if the request requires state at all */
requiresState = _rqContext.Handler is IRequiresSessionState; //originally was: _rqContext.RequiresSessionState;
// SessionIDManager may need to do a redirect if cookieless setting is AutoDetect
if (_idManager.InitializeRequest(_rqContext, false, out _rqSupportSessionIdReissue))
{
_rqAr.Complete(true, null, null);
return _rqAr;
}
/* Get sessionid */
_rqId = _idManager.GetSessionID(_rqContext);
if (requiresState)
{
// Still need to update the sliding timeout to keep session alive.
if (_rqId != null)
{
_store.ResetItemTimeout(_rqContext, _rqId);
}
_rqAr.Complete(true, null, null);
return _rqAr;
}
_rqExecutionTimeout = s_configExecutionTimeout;
/* determine if we need just read-only access */
_rqReadonly = _rqContext.Handler is IReadOnlySessionState; // originally was: _rqContext.ReadOnlySessionState;
if (_rqId != null)
{
/* get the session state corresponding to this session id */
isCompleted = getSessionStateItem();
}
else if (!skipReadingId)
{
/* if there's no id yet, create it */
bool redirected = createSessionId();
_rqIdNew = true;
if (redirected)
{
if (s_configRegenerateExpiredSessionId)
{
// See inline comments in CreateUninitializedSessionState()
createUninitializedSessionState();
}
_rqAr.Complete(true, null, null);
// commented because this is in case of inProc and OutOfProc
//if (EtwTrace.IsTraceEnabled(EtwTraceLevel.Information, EtwTraceFlags.AppSvc)) EtwTrace.Trace(EtwTraceType.ETW_TYPE_SESSION_DATA_END, _rqContext.WorkerRequest);
//return _rqAr;
}
}
if (isCompleted)
{
completeAcquireState(source, e);
_rqAr.Complete(true, null, null);
}
return _rqAr;
}
finally
{
}
}
// Called when AcquireState is done. This function will add the returned
// SessionStateStore item to the request context.
private void completeAcquireState(object source, EventArgs e)
{
if (_rqItem != null)
{
_rqSessionStateNotFound = false;
if ((_rqActionFlags & SessionStateActions.InitializeItem) != 0)
{
//Initialize an uninit item.
_rqIsNewSession = true;
}
else
{
_rqIsNewSession = false;
}
}
else
{
_rqIsNewSession = true;
_rqSessionStateNotFound = true;
// We couldn't find the session state.
if (!_rqIdNew && // If the request has a session id, that means the session state has expired
s_configRegenerateExpiredSessionId && // And we're asked to regenerate expired session
_rqSupportSessionIdReissue)
{
// And this request support session id reissue
// We will generate a new session id for this expired session state
bool redirected = createSessionId();
if (redirected)
{
// Will redirect because we've reissued a new id and it's cookieless
createUninitializedSessionState();
return;
}
}
}
initStateStoreItem(true);
if (_rqIsNewSession)
{
raiseOnStart(source, e);
}
}
private void initStateStoreItem(bool addToContext)
{
try
{
if (_rqItem == null)
{
//Creating new session state
_rqItem = _store.CreateNewStoreData(_rqContext, s_timeOut);
}
_rqSessionItems = _rqItem.Items;
if (_rqSessionItems == null)
{
throw new HttpException("Null Value for SessionStateItemCollection");
}
// No check for null because we allow our custom provider to return a null StaticObjects.
_rqStaticObjects = _rqItem.StaticObjects;
_rqSessionItems.Dirty = false;
_rqSessionState = new HttpSessionStateContainer(
_rqId,
_rqSessionItems,
_rqStaticObjects,
_rqItem.Timeout,
_rqIsNewSession,
s_configCookieless,
s_configMode,
_rqReadonly);
if (addToContext)
{
SessionStateUtility.AddHttpSessionStateToContext(_rqContext, _rqSessionState);
}
}
finally
{
}
}
private void app_EndAcquireState(IAsyncResult ar)
{
((HttpAsyncResult)ar).End();
}
}
General Overview of code above listed below:
- Module's
Init()
method will instantiate store provider and add handlers forAcquireRequest
,ReleaseRequest
andEndRequest
ofHttpApplication
's Events. also it instantiateSessionIDManger
. app_BeginAcquireState()
will create new session item increateUninitializedSessionState()
that stores new item in data store.- after that
completeAcquireState()
calls to Add new session item to theHttpContext
by callinginitStateStoreItem()
. alsoSession_Start
of Application's Global.asax will call in this method successfully. - session item successfully injected to the current context with
SessionStateUtility.AddHttpSessionStateToContext(_rqContext, _rqSessionState);