zoukankan      html  css  js  c++  java
  • Session.Abandon和Session.Clear的实现和区别

    我在网上找了一个比较贴切的描述:

    Session.Clear()就是把Session对象中的所有项目都删除了,Session对象里面啥都没有。但是Session对象还保留。Session.Abandon()就是把当前Session对象删除了,下一次就是新的Session了。(下一次新会话开始貌似并不会产生新的SESSIONID)主要的不同之处在于当使用Session.Abandon时,会调用Session_End方法(InProc模式下)。当下一个请求到来时将激发Session_Start方法。而Session.Clear只是清除Session中的所有数据并不会中止该Session,因此也不会调用那些方法。其中标红也不是很正确。

    首先我们来看一下code:

    Dictionary<string, HttpSessionState> dict = new Dictionary<string, HttpSessionState>();
    // Abandon
    dict.Remove(key);
    //Clear()
    dict[key].Clear();

    假设session存储一个字典结构,key就是我们客户端的sessionID,value 就是我们的SessionSate(它也是一个集合),调用Abandon后就把key删除了,但是clear是value里面的内容清空了。这2个方法的实现大家可以参考HttpSessionStateContainer的实现,Clear 清空集合,Abandon设置变量使其属性IsAbandoned为true。

    真正的核心code在SessionStateModule类的OnReleaseState方法里面,在有Session的Http请求中,有一个地方加载我们的session,也有一个地方保存我们的session。

      /// <devdoc>
            ///    <para>[To be supplied.]</para>
            /// </devdoc>
            void OnReleaseState(Object source, EventArgs eventArgs) {
                HttpApplication             app;
                HttpContext                 context;
                bool                        setItemCalled = false;
    
                Debug.Trace("SessionStateOnReleaseState", "Beginning SessionStateModule::OnReleaseState");
    
                Debug.Assert(!(_rqAddedCookie && !_rqIsNewSession),
                    "If session id was added to the cookie, it must be a new session.");
    
                // !!!
                // Please note that due to InProc session id optimization, this function should not
                // use _rqId directly because it can still be null.  Instead, use DelayedGetSessionId().
    
                _releaseCalled = true;
    
                app = (HttpApplication)source;
                context = app.Context;
    
                ChangeImpersonation(context, false);
    
                try {
                    if (_rqSessionState != null) {
                        bool delayedSessionState = (_rqSessionState == s_delayedSessionState);
    
                        Debug.Trace("SessionStateOnReleaseState", "Remove session state from context");
                        SessionStateUtility.RemoveHttpSessionStateFromContext(_rqContext, delayedSessionState);
    
                        /*
                         * Don't store untouched new sessions.
                         */
    
                        if (
                                    // The store doesn't have the session state.
                                    // ( Please note we aren't checking _rqIsNewSession because _rqIsNewSession
                                    // is lalso true if the item is converted from temp to perm in a GetItemXXX() call.)
                                    _rqSessionStateNotFound
    
                                    // OnStart is not defined
                                   && _sessionStartEventHandler == null
    
                                   // Nothing has been stored in session state
                                   && (delayedSessionState || !_rqSessionItems.Dirty)
                                   && (delayedSessionState || _rqStaticObjects == null || _rqStaticObjects.NeverAccessed)
                            ) {
    
                            Debug.Trace("SessionStateOnReleaseState", "Not storing unused new session.");
                        }
                        else if (_rqSessionState.IsAbandoned) {
                            Debug.Trace("SessionStateOnReleaseState", "Removing session due to abandonment, SessionId=" + _rqId);
    
                            if (_rqSessionStateNotFound) {
                                // The store provider doesn't have it, and so we don't need to remove it from the store.
    
                                // However, if the store provider supports session expiry, and we have a Session_End in global.asax,
                                // we need to explicitly call Session_End.
                                if (_supportSessionExpiry) {
                                    if (delayedSessionState) {
                                        Debug.Assert(s_allowDelayedStateStoreItemCreation, "s_allowDelayedStateStoreItemCreation");
                                        Debug.Assert(_rqItem == null, "_rqItem == null");
    
                                        InitStateStoreItem(false /*addToContext*/);
                                    }
    
                                    _onEndTarget.RaiseSessionOnEnd(ReleaseStateGetSessionID(), _rqItem);
                                }
                            }
                            else {
                                Debug.Assert(_rqItem != null, "_rqItem cannot null if it's not a new session");
    
                                // Remove it from the store because the session is abandoned.
                                _store.RemoveItem(_rqContext, ReleaseStateGetSessionID(), _rqLockId, _rqItem);
                            }
                        }
                        else if (!_rqReadonly ||
                                 (_rqReadonly &&
                                  _rqIsNewSession &&
                                  _sessionStartEventHandler != null &&
                                  !SessionIDManagerUseCookieless)) {
                            // We need to save it since it isn't read-only
                            // See Dev10 588711: Issuing a redirect from inside of Session_Start event 
                            // triggers an infinite loop when using pages with read-only session state
    
                            // We save it only if there is no error, and if something has changed (unless it's a new session)
                            if (    context.Error == null   // no error
                                    && (    _rqSessionStateNotFound
                                        || _rqSessionItems.Dirty    // SessionItems has changed.
                                        || (_rqStaticObjects != null && !_rqStaticObjects.NeverAccessed) // Static objects have been accessed
                                        || _rqItem.Timeout != _rqSessionState.Timeout   // Timeout value has changed
                                        )
                                ) {
    
                                if (delayedSessionState) {
                                    Debug.Assert(_rqIsNewSession, "Saving a session and delayedSessionState is true: _rqIsNewSession must be true");
                                    Debug.Assert(s_allowDelayedStateStoreItemCreation, "Saving a session and delayedSessionState is true: s_allowDelayedStateStoreItemCreation");
                                    Debug.Assert(_rqItem == null, "Saving a session and delayedSessionState is true: _rqItem == null");
    
                                    InitStateStoreItem(false /*addToContext*/);
                                }
    
    #if DBG
                                if (_rqSessionItems.Dirty) {
                                    Debug.Trace("SessionStateOnReleaseState", "Setting new session due to dirty SessionItems, SessionId=" + _rqId);
                                }
                                else if (_rqStaticObjects != null && !_rqStaticObjects.NeverAccessed) {
                                    Debug.Trace("SessionStateOnReleaseState", "Setting new session due to accessed Static Objects, SessionId=" + _rqId);
                                }
                                else if (_rqSessionStateNotFound) {
                                    Debug.Trace("SessionStateOnReleaseState", "Setting new session because it's not found, SessionId=" + _rqId);
                                }
                                else {
                                    Debug.Trace("SessionStateOnReleaseState", "Setting new session due to options change, SessionId=" + _rqId +
                                                "
    	_rq.timeout=" + _rqItem.Timeout.ToString(CultureInfo.InvariantCulture) +
                                                ", _rqSessionState.timeout=" + _rqSessionState.Timeout.ToString(CultureInfo.InvariantCulture));
                                }
    #endif
                                if (_rqItem.Timeout != _rqSessionState.Timeout) {
                                    _rqItem.Timeout = _rqSessionState.Timeout;
                                }
    
                                s_sessionEverSet = true;
                                setItemCalled = true;
                                _store.SetAndReleaseItemExclusive(_rqContext, ReleaseStateGetSessionID(), _rqItem, _rqLockId, _rqSessionStateNotFound);
                            }
                            else {
                                // Can't save it because of various reason.  Just release our exclusive lock on it.
                                Debug.Trace("SessionStateOnReleaseState", "Release exclusive lock on session, SessionId=" + _rqId);
    
                                if (!_rqSessionStateNotFound) {
                                    Debug.Assert(_rqItem != null, "_rqItem cannot null if it's not a new session");
                                    _store.ReleaseItemExclusive(_rqContext, ReleaseStateGetSessionID(), _rqLockId);
                                }
                            }
                        }
    #if DBG
                        else {
                            Debug.Trace("SessionStateOnReleaseState", "Session is read-only, ignoring SessionId=" + _rqId);
                        }
    #endif
    
                        Debug.Trace("SessionStateOnReleaseState", "Returning from SessionStateModule::OnReleaseState");
                    }
    
                    if (_rqAddedCookie && !setItemCalled && context.Response.IsBuffered()) {
                        _idManager.RemoveSessionID(_rqContext);
                    }
    
                }
                finally {
                    RestoreImpersonation();
                }
    
                // WOS 1679798: PERF: Session State Module should disable EndRequest on successful cleanup
                bool implementsIRequiresSessionState = context.RequiresSessionState;
                if (HttpRuntime.UseIntegratedPipeline 
                    && (context.NotificationContext.CurrentNotification == RequestNotification.ReleaseRequestState) 
                    && (s_canSkipEndRequestCall || !implementsIRequiresSessionState)) {
                    context.DisableNotifications(RequestNotification.EndRequest, 0 /*postNotifications*/);
                    _acquireCalled = false;
                    _releaseCalled = false;
                    ResetPerRequestFields();
                }
            }
    View Code

    其中主要的code是:

     else if (_rqSessionState.IsAbandoned) {
                            Debug.Trace("SessionStateOnReleaseState", "Removing session due to abandonment, SessionId=" + _rqId);
    
                            if (_rqSessionStateNotFound) {
                                // The store provider doesn't have it, and so we don't need to remove it from the store.
    
                                // However, if the store provider supports session expiry, and we have a Session_End in global.asax,
                                // we need to explicitly call Session_End.
                                if (_supportSessionExpiry) {
                                    if (delayedSessionState) {
                                        Debug.Assert(s_allowDelayedStateStoreItemCreation, "s_allowDelayedStateStoreItemCreation");
                                        Debug.Assert(_rqItem == null, "_rqItem == null");
    
                                        InitStateStoreItem(false /*addToContext*/);
                                    }
    
                                    _onEndTarget.RaiseSessionOnEnd(ReleaseStateGetSessionID(), _rqItem);
                                }
                            }
                            else {
                                Debug.Assert(_rqItem != null, "_rqItem cannot null if it's not a new session");
    
                                // Remove it from the store because the session is abandoned.
                                _store.RemoveItem(_rqContext, ReleaseStateGetSessionID(), _rqLockId, _rqItem);
                            }
                        }

    if (_rqAddedCookie && !setItemCalled && context.Response.IsBuffered()) {
    _idManager.RemoveSessionID(_rqContext);
    }

    _rqAddedCookie 一般情况下为false,所以SessionID 默认也就没有被移除。也就是调用Abandon方法默认Session ID是不会改变的。 _onEndTarget.RaiseSessionOnEnd(ReleaseStateGetSessionID(), _rqItem);就是调用我们的Session_End方法。看到这里大家应该知道什么情况调用Session_End,什么有调用 _store.RemoveItem(_rqContext, ReleaseStateGetSessionID(), _rqLockId, _rqItem); 还有后面   _store.SetAndReleaseItemExclusive(_rqContext, ReleaseStateGetSessionID(), _rqItem, _rqLockId, _rqSessionStateNotFound);这个方法也很重要哦, 就是保存我们的Session大家可以参考 asp.net mvc Session RedisSessionStateProvider锁的实现

  • 相关阅读:
    XV Open Cup named after E.V. Pankratiev. GP of Central Europe (AMPPZ-2014)--B.Petrol
    XVI Open Cup named after E.V. Pankratiev. GP of Eurasia
    Petrozavodsk Winter Camp, Warsaw U, 2014, A The Carpet
    训练日志4
    训练日志3
    训练日志2
    多校中期总结
    训练日志
    计算几何学习12 + 组队训练
    计算几何学习11
  • 原文地址:https://www.cnblogs.com/majiang/p/6777715.html
Copyright © 2011-2022 走看看