会话在页面上下文中不可用(实现了自定义会话httpModule)

时间:2015-03-11 13:49:38

标签: c# asp.net session iis httpmodule

我实施了自定义会话状态模块,并按如下方式添加到应用程序中(web.config):

<system.webServer>
    <modules>
        <remove name="Session" />
        <add name="Session" type="CustomServerModules.StateServer.SessionState.SessionStateModule" preCondition="managedHandler" />
    </modules>
</system.webServer>

我的IIS应用程序池设置为Integrated v4.0
我将SessionStateData(确切地说是HttpSessionStateContainer对象)添加到HttpContext事件BeginAcquireState上(根据Microsoft的SessionStateModule):

SessionStateUtility.AddHttpSessionStateToContext(_rqContext, _rqSessionState);

但我的问题是Session Page中的对象没有值,它会引发异常:

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.

此外HttpContext.Current.Session为空。

现在问题是:为什么在自定义模式下应用程序页面中无法访问会话?在创建和启动HttpApplications和Page实例以跟踪Session对象时,如何跟踪IIS和ASP.NET的行为?

更新
我包含了我的Session HttpModule的 AcquireRequest 方式,如下所示。在此部分中,新会话将添加到HttpContextSession_Start将添加:

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();
    }
}

以下列出的代码概述:

  1. 模块的Init()方法将实例化商店提供商并添加AcquireRequestReleaseRequestEndRequestHttpApplication事件的处理程序。它也实例化SessionIDManger
  2. app_BeginAcquireState()将在createUninitializedSessionState()中创建新的会话项,用于在数据存储中存储新项目。
  3. 之后completeAcquireState()通过调用HttpContext调用将新会话项添加到initStateStoreItem()。应用程序的Global.asax Session_Start也会成功调用此方法。
  4. 会话项已使用SessionStateUtility.AddHttpSessionStateToContext(_rqContext, _rqSessionState);
  5. 成功注入当前上下文

0 个答案:

没有答案