我在网上找了一个比较贴切的描述:
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 + "\n\t_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(); } }
其中主要的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锁的实现
今天的文章Session.Abandon和Session.Clear的实现和区别分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/24400.html