西西軟件下載最安全的下載網(wǎng)站、值得信賴(lài)的軟件下載站!

首頁(yè)編程開(kāi)發(fā)ASP.NET → Asp.net 開(kāi)發(fā)中Session是如何實(shí)現(xiàn)存儲(chǔ)的?

Asp.net 開(kāi)發(fā)中Session是如何實(shí)現(xiàn)存儲(chǔ)的?

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:西西整理時(shí)間:2012/11/28 21:32:54字體大。A-A+

作者:西西點(diǎn)擊:0次評(píng)論:0次標(biāo)簽: Session

  • 類(lèi)型:磁盤(pán)工具大。18.8M語(yǔ)言:中文 評(píng)分:5.0
  • 標(biāo)簽:
立即下載

我們還是簡(jiǎn)單的來(lái)復(fù)習(xí)一下Session吧:Session的數(shù)據(jù)時(shí)保存在服務(wù)器端,并且每個(gè)客戶端對(duì)應(yīng)不同Session。那么Session究竟是如何保存,如何區(qū)分客服端的了?我們還是沿用以前的方法來(lái)講吧,以一個(gè)demo開(kāi)始:

protected void Page_Load(object sender, EventArgs e)  
       {  
           string name = this.Request["Name"];  
           object sessionName = Session["Name"];  
           if (string.IsNullOrEmpty(name) && sessionName==null)  
           {  
               Response.Write("Please Enter your name!");  
           }  
           else   
           {  
               if (sessionName == null)  
               {  
                   Session.Add("Name", name);  
                   Response.Write("Set Session name and Session ID:"+Session.SessionID);  
               }  
               else  
               {  
                   Response.Write("Get Session Name and Session ID:"+ Session.SessionID);  
               }  
               Response.Write(" Name:" + name);  
           }  
       }

 假設(shè)我們的請(qǐng)求路徑為http://localhost:18385/WebForm1.aspx?name=majiang

第一次請(qǐng)求數(shù)據(jù)如下:

第二次請(qǐng)求數(shù)據(jù)了:

這里我們看見(jiàn)在第一次請(qǐng)求的返回頭里面有一個(gè)ASP.NET_SessionId,在第二次請(qǐng)求過(guò)程中這個(gè)請(qǐng)求頭里面也含有ASP.NET_SessionId,并且它的值剛好是Session.SessionID(我這里用的是asp.net4.5),我們可以猜測(cè)這個(gè)ASP.NET_SessionId就是用來(lái)區(qū)分不同的客戶端請(qǐng)求。那么這個(gè)值是什么時(shí)候生成的又是什么時(shí)候輸出的了?

首先我們需要知道我們用到的那個(gè)Session具體在什么地方定義的,其實(shí)它是定義于HttpContext的Session屬性中,我們一般的page也只是調(diào)用這個(gè)屬性而已。

public HttpSessionState Session
{
    get
    {
        if (this.HasWebSocketRequestTransitionCompleted)
        {
            return null;
        }
        if (this._sessionStateModule != null)
        {
            lock (this)
            {
                if (this._sessionStateModule != null)
                {
                    this._sessionStateModule.InitStateStoreItem(true);
                    this._sessionStateModule = null;
                }
            }
        }
        return (HttpSessionState) this.Items["AspSession"];
    }
}
 
這里用到一個(gè)_sessionStateModule的變量,那么究竟在什么地方操作它們的了?在HttpContext中有兩個(gè)操作sessionStateModule方法如下:
  internal void AddDelayedHttpSessionState(SessionStateModule module)
    {
        if (this._sessionStateModule != null)
        {
            throw new HttpException(SR.GetString("Cant_have_multiple_session_module"));
        }
        this._sessionStateModule = module;
    }

    internal void RemoveDelayedHttpSessionState()
    {
        this._sessionStateModule = null;
    }

這兩個(gè)方法干什么的我就不說(shuō)了,它們是在什么地方調(diào)用的了。如果你開(kāi)發(fā)過(guò)asp.net,那么你應(yīng)該知道在SessionStateModule 類(lèi),它是一個(gè)IHttpModule的實(shí)現(xiàn)者專(zhuān)門(mén)用來(lái)管理Session的,在這個(gè)類(lèi)中有一個(gè)InitModuleFromConfig方法,該方法主要是在該類(lèi)的Init中調(diào)用,如喪我們來(lái)看看它的具體實(shí)現(xiàn)吧:

private void InitModuleFromConfig(HttpApplication app, SessionStateSection config) { if (config.Mode != SessionStateMode.Off) { app.AddOnAcquireRequestStateAsync(new BeginEventHandler(this.BeginAcquireState), new EndEventHandler(this.EndAcquireState)); app.ReleaseRequestState += new EventHandler(this.OnReleaseState); app.EndRequest += new EventHandler(this.OnEndRequest); this._partitionResolver = this.InitPartitionResolver(config); switch (config.Mode) { case SessionStateMode.InProc: if (HttpRuntime.UseIntegratedPipeline) { s_canSkipEndRequestCall = true; } this._store = new InProcSessionStateStore(); this._store.Initialize(null, null); break; case SessionStateMode.StateServer: if (HttpRuntime.UseIntegratedPipeline) { s_canSkipEndRequestCall = true; } this._store = new OutOfProcSessionStateStore(); ((OutOfProcSessionStateStore) this._store).Initialize(null, null, this._partitionResolver); break; case SessionStateMode.SQLServer: this._store = new SqlSessionStateStore(); ((SqlSessionStateStore) this._store).Initialize(null, null, this._partitionResolver); break; case SessionStateMode.Custom: this._store = this.InitCustomStore(config); break; } this._idManager = this.InitSessionIDManager(config); if (((config.Mode == SessionStateMode.InProc) || (config.Mode == SessionStateMode.StateServer)) && this._usingAspnetSessionIdManager) { this._ignoreImpersonation = true; } } }

這里主要是設(shè)置 this._store和  this._idManager 它們兩個(gè)變量,其中 this._store的設(shè)置根據(jù)Session的存儲(chǔ)類(lèi)型不同設(shè)置為不同的實(shí)例,這里的存儲(chǔ)方式有以下四種

public enum SessionStateMode
{
    Off,
    InProc,
    StateServer,
    SQLServer,
    Custom
}
默認(rèn)的是SessionStateMode.InProc,所以默認(rèn)的this._store是一個(gè)InProcSessionStateStore實(shí)例,而this._idManager默認(rèn)是一個(gè)SessionIDManager實(shí)例。這個(gè)方法結(jié)束后我們的 this._store和  this._idManager這兩個(gè)變量就已經(jīng)有值了。在SessionStateModule類(lèi)中還有一個(gè)很重要的方法 BeginAcquireState:

private IAsyncResult BeginAcquireState(object source, EventArgs e, AsyncCallback cb, object extraData) { IAsyncResult result; bool sessionStateItem = true; bool flag3 = false; this._acquireCalled = true; this._releaseCalled = false; this.ResetPerRequestFields(); this._rqContext = ((HttpApplication) source).Context; this._rqAr = new HttpAsyncResult(cb, extraData); this.ChangeImpersonation(this._rqContext, false); try { if (EtwTrace.IsTraceEnabled(4, 8)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_SESSION_DATA_BEGIN, this._rqContext.WorkerRequest); } this._store.InitializeRequest(this._rqContext); bool requiresSessionState = this._rqContext.RequiresSessionState; if (this._idManager.InitializeRequest(this._rqContext, false, out this._rqSupportSessionIdReissue)) { this._rqAr.Complete(true, null, null); if (EtwTrace.IsTraceEnabled(4, 8)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_SESSION_DATA_END, this._rqContext.WorkerRequest); } return this._rqAr; } if ((s_allowInProcOptimization && !s_sessionEverSet) && (!requiresSessionState || !((SessionIDManager) this._idManager).UseCookieless(this._rqContext))) { flag3 = true; } else { this._rqId = this._idManager.GetSessionID(this._rqContext); } if (!requiresSessionState) { if (this._rqId != null) { this._store.ResetItemTimeout(this._rqContext, this._rqId); } this._rqAr.Complete(true, null, null); if (EtwTrace.IsTraceEnabled(4, 8)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_SESSION_DATA_END, this._rqContext.WorkerRequest); } return this._rqAr; } this._rqExecutionTimeout = this._rqContext.Timeout; if (this._rqExecutionTimeout == DEFAULT_DBG_EXECUTION_TIMEOUT) { this._rqExecutionTimeout = s_configExecutionTimeout; } this._rqReadonly = this._rqContext.ReadOnlySessionState; if (this._rqId != null) { sessionStateItem = this.GetSessionStateItem(); } else if (!flag3) { bool flag4 = this.CreateSessionId(); this._rqIdNew = true; if (flag4) { if (s_configRegenerateExpiredSessionId) { this.CreateUninitializedSessionState(); } this._rqAr.Complete(true, null, null); if (EtwTrace.IsTraceEnabled(4, 8)) { EtwTrace.Trace(EtwTraceType.ETW_TYPE_SESSION_DATA_END, this._rqContext.WorkerRequest); } return this._rqAr; } } if (sessionStateItem) { this.CompleteAcquireState(); this._rqAr.Complete(true, null, null); } result = this._rqAr; } finally { this.RestoreImpersonation(); } return result; }

在這個(gè)方法中有以下3句比較重要

    this._rqId = this._idManager.GetSessionID(this._rqContext);
   sessionStateItem = this.GetSessionStateItem();
    this.CompleteAcquireState();

第一句獲取SessionID,第二句貨物SessionStateItem,第三句主要是調(diào)用一個(gè)CompleteAcquireState方法,而這個(gè)方法里面有一句  SessionStateUtility.AddDelayedHttpSessionStateToContext(this._rqContext, this);或則this.InitStateStoreItem(true); 這個(gè)方法主要對(duì)應(yīng)一句

 SessionStateUtility.AddHttpSessionStateToContext(this._rqContext, this._rqSessionState);,在這個(gè)類(lèi)中還有一個(gè)方法OnReleaseState里面有這么一句

 SessionStateUtility.RemoveHttpSessionStateFromContext(this._rqContext, delayed);

我們首先來(lái)可看看SessionStateUtility的AddHttpSessionStateToContext、RemoveHttpSessionStateFromContext方法的實(shí)現(xiàn)吧。

internal static void AddDelayedHttpSessionStateToContext(HttpContext context, SessionStateModule module){ context.AddDelayedHttpSessionState(module);}internal void AddDelayedHttpSessionState(SessionStateModule module){ if (this._sessionStateModule != null) { throw new HttpException(SR.GetString("Cant_have_multiple_session_module")); } this._sessionStateModule = module;}public static void AddHttpSessionStateToContext(HttpContext context, IHttpSessionState container) { HttpSessionState state = new HttpSessionState(container); try { context.Items.Add("AspSession", state); } catch (ArgumentException) { throw new HttpException(SR.GetString("Cant_have_multiple_session_module")); } } internal static void RemoveHttpSessionStateFromContext(HttpContext context, bool delayed) { if (delayed) { context.RemoveDelayedHttpSessionState(); } else { context.Items.Remove("AspSession"); } }

其中HttpContext的RemoveDelayedHttpSessionState就一句    this._sessionStateModule = null;我想對(duì)于SessionStateUtility里面的這幾個(gè)方法我就不多說(shuō)吧,很簡(jiǎn)單。

我們還是回頭看看前面那2句吧,

public string GetSessionID(HttpContext context){ string id = null; this.CheckInitializeRequestCalled(context); if (this.UseCookieless(context)) { return (string) context.Items["AspCookielessSession"]; } HttpCookie cookie = context.Request.Cookies[Config.CookieName]; if ((cookie != null) && (cookie.Value != null)) { id = this.Decode(cookie.Value); if ((id != null) && !this.ValidateInternal(id, false)) { id = null; } } return id;}

默認(rèn)情況下我們的cookie是可用的,這里的Config.CookieName實(shí)際上就是SessionStateSection的CookieName屬性

[ConfigurationProperty("cookieName", DefaultValue="ASP.NET_SessionId")]public string CookieName{ get { return (string) base[_propCookieName]; } set { base[_propCookieName] = value; }}

到這里大家應(yīng)該知道為什么Http請(qǐng)求和返回關(guān)于Session對(duì)應(yīng)Cookie的id是ASP.NET_SessionId了吧。不過(guò)大家要注意一點(diǎn)這里的SessionIDManager 在操作cookie做了一些數(shù)據(jù)驗(yàn)證處理,如果在特殊情況需要自定義驗(yàn)證規(guī)則我們可以自己來(lái)實(shí)現(xiàn)ISessionIDManager接口。這里我們可以看到第一次請(qǐng)求是沒(méi)有sessionid的,所以sessionStateItem = this.GetSessionStateItem();這句代碼不會(huì)執(zhí)行,sessionStateItem默認(rèn)為true,但是第二次請(qǐng)求時(shí)有sessionid這句代碼就會(huì)執(zhí)行。GetSessionStateItem()的實(shí)現(xiàn)這里我們就忽略了吧,這個(gè)方法設(shè)置一個(gè)SessionStateStoreData的實(shí)例 this._rqItem ,如果 this._rqItem為null則返回false。一般我們的Session都是可讀寫(xiě)的。GetSessionStateItem方法主要是調(diào)用  this._rqItem = this._store.GetItemExclusive(this._rqContext, this._rqId, out flag2, out span, out this._rqLockId, out this._rqActionFlags);

現(xiàn)在我們回到CompleteAcquireState方法中來(lái):

  if (flag)
            {
                SessionStateUtility.AddDelayedHttpSessionStateToContext(this._rqContext, this);
                this._rqSessionState = s_delayedSessionState;
            }
            else
            {
                this.InitStateStoreItem(true); //SessionStateUtility.AddHttpSessionStateToContext(this._rqContext, this._rqSessionState);
            }

這里是flag默認(rèn)是false,里面具體判斷就不說(shuō),InitStateStoreItem方法主要代碼:

if (this._rqItem == null)
            {
                this._rqItem = this._store.CreateNewStoreData(this._rqContext, s_timeout);
            }

this._rqSessionItems = this._rqItem.Items;

   this._rqSessionState = new HttpSessionStateContainer(this, this._rqId, this._rqSessionItems, this._rqStaticObjects, this._rqItem.Timeout, this._rqIsNewSession, s_configCookieless, s_configMode, this._rqReadonly);
            SessionStateUtility.AddHttpSessionStateToContext(this._rqContext, this._rqSessionState);

這里InProcSessionStateStore 的CreateNewStoreData方法實(shí)際就是調(diào)用SessionStateUtility.CreateLegitStoreData:

internal static SessionStateStoreData CreateLegitStoreData(HttpContext context, ISessionStateItemCollection sessionItems, HttpStaticObjectsCollection staticObjects, int timeout){ if (sessionItems == null) { sessionItems = new SessionStateItemCollection(); } if ((staticObjects == null) && (context != null)) { staticObjects = GetSessionStaticObjects(context); } return new SessionStateStoreData(sessionItems, staticObjects, timeout);}

其中SessionStateItemCollection的定義如下:

public sealed class SessionStateItemCollection : NameObjectCollectionBase, ISessionStateItemCollection, ICollection, IEnumerable

這里創(chuàng)建了一個(gè)  HttpSessionStateContainer實(shí)例。我想大家到這里就應(yīng)該明白我們的Session實(shí)際上就是一個(gè)HttpSessionStateContainer實(shí)例。

好現(xiàn)在我來(lái)看 Session.SessionID這個(gè)是怎么實(shí)現(xiàn)的
public string SessionID
{
    get
    {
        if (this._id == null)
        {
            this._id = this._stateModule.DelayedGetSessionId();
        }
        return this._id;
    }
}

而SessionStateModule的DelayedGetSessionId方法實(shí)現(xiàn)如下:

internal string DelayedGetSessionId()
{
    this.ChangeImpersonation(this._rqContext, false);
    try
    {
        this._rqId = this._idManager.GetSessionID(this._rqContext);
        if (this._rqId == null)
        {
            this.CreateSessionId();
        }
    }
    finally
    {
        this.RestoreImpersonation();
    }
    return this._rqId;
}
這里的CreateSessionId具體是怎么創(chuàng)建我就不說(shuō)了吧,知道它是真正創(chuàng)建sessionid的就可以。而session的實(shí)際操作都是在ISessionStateItemCollection里面如HttpSessionStateContainer的Add方法:

public void Add(string name, object value)
{
    this._sessionItems[name] = value;
}

而這里的_sessionItems實(shí)際上是this._rqItem.Items,本來(lái)想忽略_rqItem的創(chuàng)建,看來(lái)這個(gè)實(shí)例比較強(qiáng)啊。

 this._rqItem = this._store.GetItemExclusive(this._rqContext, this._rqId, out flag2, out span, out this._rqLockId, out this._rqActionFlags);
        if ((((this._rqItem == null) && !flag2) && (this._rqId != null)) && ((s_configCookieless != HttpCookieMode.UseUri) || !s_configRegenerateExpiredSessionId))
        {
            this.CreateUninitializedSessionState();
            this._rqItem = this._store.GetItemExclusive(this._rqContext, this._rqId, out flag2, out span, out this._rqLockId, out this._rqActionFlags);
        }

這里的CreateUninitializedSessionState方法實(shí)際就是調(diào)用this._store.CreateUninitializedItem(this._rqContext, this._rqId, s_timeout);

我們前面知道this._store這個(gè)可以取很多實(shí)例的,是SessionStateStoreProviderBase類(lèi)型,這里我們也已默認(rèn)的 InProcSessionStateStore(繼承SessionStateStoreProviderBase)來(lái)說(shuō)說(shuō)吧,相關(guān)方法:

private SessionStateStoreData DoGet(HttpContext context, string id, bool exclusive, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
{
    bool flag;
    string key = this.CreateSessionStateCacheKey(id);
    InProcSessionState state = (InProcSessionState) HttpRuntime.CacheInternal.Get(key);
    if (state == null)
    {
        return null;
    }
  ......
    return SessionStateUtility.CreateLegitStoreData(context, state._sessionItems, state._staticObjects, state._timeout);
}

public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
{
    string key = this.CreateSessionStateCacheKey(id);
    SessionIDManager.CheckIdLength(id, true);
    InProcSessionState state = new InProcSessionState(null, null, timeout, false, DateTime.MinValue, NewLockCookie, 1);
    try
    {
    }
    finally
    {
        if (HttpRuntime.CacheInternal.UtcAdd(key, state, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, timeout, 0), CacheItemPriority.NotRemovable, this._callback) == null)
        {
            PerfCounters.IncrementCounter(AppPerfCounter.SESSIONS_TOTAL);
            PerfCounters.IncrementCounter(AppPerfCounter.SESSIONS_ACTIVE);
        }
    }
}

現(xiàn)在我們終于明白一個(gè)Sessionid對(duì)應(yīng)一個(gè)SessionStateStoreData,所以它能區(qū)分不同的用戶請(qǐng)求,這里的id就是我們前面的this._rqId了。

現(xiàn)在我們也總結(jié)一下吧,我們的HttpContext的Session屬性實(shí)際上是一個(gè)HttpSessionStateContainer實(shí)例(HttpSessionStateContainer繼承IHttpSessionState),而它數(shù)據(jù)成員都是保存在ISessionStateItemCollection實(shí)例中,每一次http請(qǐng)求我們都會(huì)去獲取它的Sessionid,第一次請(qǐng)求sessionid問(wèn)null,我們沒(méi)有對(duì)應(yīng)的SessionStateStoreData數(shù)據(jù),這時(shí)我們?cè)赟essionStateModule的 InitStateStoreItem方法調(diào)用SessionStateStoreProviderBase的CreateNewStoreData方法來(lái)創(chuàng)建一個(gè)SessionStateStoreData實(shí)例,其中該實(shí)例有一個(gè)成員變量類(lèi)型是ISessionStateItemCollection用來(lái)保存用戶session的數(shù)據(jù)。同一個(gè)用戶第二次請(qǐng)求我們能獲取到它的sessionid,默認(rèn)也能獲取到SessionStateStoreData實(shí)例(session過(guò)期則取不到)。一個(gè)用戶對(duì)應(yīng)一個(gè)SessionStateStoreData,每個(gè)SessionStateStoreData里面有一個(gè)ISessionStateItemCollection實(shí)例用來(lái)保存用戶數(shù)據(jù),至于sessionid也就是用戶身份的區(qū)別依賴(lài)于ISessionIDManager的實(shí)現(xiàn)。

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門(mén)評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(0)

    昵稱(chēng):
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)
    推薦文章

    沒(méi)有數(shù)據(jù)

    最新文章
      沒(méi)有數(shù)據(jù)