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

首頁編程開發(fā)ASP.NET → Asp.net 開發(fā)中Session是如何實現(xiàn)存儲的?

Asp.net 開發(fā)中Session是如何實現(xiàn)存儲的?

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

作者:西西點擊:0次評論:0次標(biāo)簽: Session

  • 類型:磁盤工具大小:18.8M語言:中文 評分:5.0
  • 標(biāo)簽:
立即下載

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

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è)我們的請求路徑為http://localhost:18385/WebForm1.aspx?name=majiang

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

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

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

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

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"];
    }
}
 
這里用到一個_sessionStateModule的變量,那么究竟在什么地方操作它們的了?在HttpContext中有兩個操作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;
    }

這兩個方法干什么的我就不說了,它們是在什么地方調(diào)用的了。如果你開發(fā)過asp.net,那么你應(yīng)該知道在SessionStateModule 類,它是一個IHttpModule的實現(xiàn)者專門用來管理Session的,在這個類中有一個InitModuleFromConfig方法,該方法主要是在該類的Init中調(diào)用,如喪我們來看看它的具體實現(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 它們兩個變量,其中 this._store的設(shè)置根據(jù)Session的存儲類型不同設(shè)置為不同的實例,這里的存儲方式有以下四種

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

在這個方法中有以下3句比較重要

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

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

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

 SessionStateUtility.RemoveHttpSessionStateFromContext(this._rqContext, delayed);

我們首先來可看看SessionStateUtility的AddHttpSessionStateToContext、RemoveHttpSessionStateFromContext方法的實現(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;我想對于SessionStateUtility里面的這幾個方法我就不多說吧,很簡單。

我們還是回頭看看前面那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實際上就是SessionStateSection的CookieName屬性

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

到這里大家應(yīng)該知道為什么Http請求和返回關(guān)于Session對應(yīng)Cookie的id是ASP.NET_SessionId了吧。不過大家要注意一點這里的SessionIDManager 在操作cookie做了一些數(shù)據(jù)驗證處理,如果在特殊情況需要自定義驗證規(guī)則我們可以自己來實現(xiàn)ISessionIDManager接口。這里我們可以看到第一次請求是沒有sessionid的,所以sessionStateItem = this.GetSessionStateItem();這句代碼不會執(zhí)行,sessionStateItem默認(rèn)為true,但是第二次請求時有sessionid這句代碼就會執(zhí)行。GetSessionStateItem()的實現(xiàn)這里我們就忽略了吧,這個方法設(shè)置一個SessionStateStoreData的實例 this._rqItem ,如果 this._rqItem為null則返回false。一般我們的Session都是可讀寫的。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方法中來:

  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,里面具體判斷就不說,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方法實際就是調(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)建了一個  HttpSessionStateContainer實例。我想大家到這里就應(yīng)該明白我們的Session實際上就是一個HttpSessionStateContainer實例。

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

而SessionStateModule的DelayedGetSessionId方法實現(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)建我就不說了吧,知道它是真正創(chuàng)建sessionid的就可以。而session的實際操作都是在ISessionStateItemCollection里面如HttpSessionStateContainer的Add方法:

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

而這里的_sessionItems實際上是this._rqItem.Items,本來想忽略_rqItem的創(chuà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方法實際就是調(diào)用this._store.CreateUninitializedItem(this._rqContext, this._rqId, s_timeout);

我們前面知道this._store這個可以取很多實例的,是SessionStateStoreProviderBase類型,這里我們也已默認(rèn)的 InProcSessionStateStore(繼承SessionStateStoreProviderBase)來說說吧,相關(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)在我們終于明白一個Sessionid對應(yīng)一個SessionStateStoreData,所以它能區(qū)分不同的用戶請求,這里的id就是我們前面的this._rqId了。

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

    相關(guān)評論

    閱讀本文后您有什么感想? 已有人給出評價!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過難過
    • 5 囧
    • 3 圍觀圍觀
    • 2 無聊無聊

    熱門評論

    最新評論

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

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

    沒有數(shù)據(jù)

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