豪仕知识网--知识就是力量!

微信
手机版
生活常识

Asp.net开发中Session是如何实现存储的-asp.net session登录界面

作者 :东方不败 2024-01-06 12:32:25 围观 : 评论

Asp.net开发中Session是如何实现存储的-asp.net session登录界面

豪士君测试所用平台

纪录美好生活,一起观趣事,这里包罗IT知识,豪仕知识网是信息的海洋,有你听不到的故事,接下来我们一起来看看Asp.net开发中Session是如何实现存储的。

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

我们还是简单的来复习一下Session吧:Session的数据时保存在服务器端,并且每个客户端对应不同Session。那么Session究竟是如何保存,如何区分客服端的了?我们还是沿用以前的方法来讲吧,以一个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); } }

假设我们的请求路径为http://localhost:18385/WebForm1.aspx?name=majiang

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

第一次请求数据如下:

第二次请求数据了:

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识http://www.Haoz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

这里我们看见在第一次请求的返回头里面有一个ASP.NET_SessionId,在第二次请求过程中这个请求头里面也含有ASP.NET_SessionId,并且它的值刚好是Session.SessionID(我这里用的是asp.net4.5),我们可以猜测这个ASP.NET_SessionId就是用来区分不同的客户端请求。那么这个值是什么时候生成的又是什么时候输出的了?

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

首先我们需要知道我们用到的那个Session具体在什么地方定义的,其实它是定义于HttpContext的Session属性中,我们一般的page也只是调用这个属性而已。

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

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

这两个方法干什么的我就不说了,它们是在什么地方调用的了。如果你开发过asp.net,那么你应该知道在SessionStateModule 类,它是一个IHttpModule的实现者专门用来管理Session的,在这个类中有一个InitModuleFromConfig方法,该方法主要是在该类的Init中调用,如丧我们来看看它的具体实现吧:

HTTP://WWW.haoz.net◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐豪仕知识网

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

这里主要是设置this._store和 this._idManager 它们两个变量,其中this._store的设置根据Session的存储类型不同设置为不同的实例,这里的存储方式有以下四种

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

public enum SessionStateMode{ Off, InProc, StateServer, SQLServer, Custom}默认的是SessionStateMode.InProc,所以默认的this._store是一个InProcSessionStateStore实例,而this._idManager默认是一个SessionIDManager实例。这个方法结束后我们的this._store和 this._idManager这两个变量就已经有值了。在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句比较重要

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

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

第一句获取SessionID,第二句货物SessionStateItem,第三句主要是调用一个CompleteAcquireState方法,而这个方法里面有一句 SessionStateUtility.AddDelayedHttpSessionStateToContext(this._rqContext, this);或则this.InitStateStoreItem(true); 这个方法主要对应一句

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

SessionStateUtility.AddHttpSessionStateToContext(this._rqContext, this._rqSessionState);,在这个类中还有一个方法OnReleaseState里面有这么一句

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

SessionStateUtility.RemoveHttpSessionStateFromContext(this._rqContext, delayed);

我们首先来可看看SessionStateUtility的AddHttpSessionStateToContext、RemoveHttpSessionStateFromContext方法的实现吧。

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

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HTTP://WWW.hAoz.net███████████████████████████东方金报网

其中HttpContext的RemoveDelayedHttpSessionState就一句 this._sessionStateModule = null;我想对于SessionStateUtility里面的这几个方法我就不多说吧,很简单。

我们还是回头看看前面那2句吧,

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HTTP://WWW.hAoz.net███████████████████████████东方金报网

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

默认情况下我们的cookie是可用的,这里的Config.CookieName实际上就是SessionStateSection的CookieName属性

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

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

到这里大家应该知道为什么Http请求和返回关于Session对应Cookie的id是ASP.NET_SessionId了吧。不过大家要注意一点这里的SessionIDManager 在操作cookie做了一些数据验证处理,如果在特殊情况需要自定义验证规则我们可以自己来实现ISessionIDManager接口。这里我们可以看到第一次请求是没有sessionid的,所以sessionStateItem = this.GetSessionStateItem();这句代码不会执行,sessionStateItem默认为true,但是第二次请求时有sessionid这句代码就会执行。GetSessionStateItem()的实现这里我们就忽略了吧,这个方法设置一个SessionStateStoreData的实例this._rqItem ,如果this._rqItem为null则返回false。一般我们的Session都是可读写的。GetSessionStateItem方法主要是调用 this._rqItem = this._store.GetItemExclusive(this._rqContext, this._rqId, out flag2, out span, out this._rqLockId, out this._rqActionFlags);现在我们回到CompleteAcquireState方法中来:

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HTTP://WWW.hAoz.net███████████████████████████东方金报网

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

这里是flag默认是false,里面具体判断就不说,InitStateStoreItem方法主要代码:

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

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

this._rqSessionItems = this._rqItem.Items;

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

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

这里InProcSessionStateStore 的CreateNewStoreData方法实际就是调用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的定义如下:

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

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

●☛█▼▲豪仕知识网◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲

这里创建了一个 HttpSessionStateContainer实例。我想大家到这里就应该明白我们的Session实际上就是一个HttpSessionStateContainer实例。

好现在我来看Session.SessionID这个是怎么实现的public string SessionID{ get { if (this._id == null) {this._id = this._stateModule.DelayedGetSessionId(); } return this._id; }}

而SessionStateModule的DelayedGetSessionId方法实现如下:

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

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具体是怎么创建我就不说了吧,知道它是真正创建sessionid的就可以。而session的实际操作都是在ISessionStateItemCollection里面如HttpSessionStateContainer的Add方法:

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

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

而这里的_sessionItems实际上是this._rqItem.Items,本来想忽略_rqItem的创建,看来这个实例比较强啊。

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

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HTTP://WWW.hAoz.net███████████████████████████东方金报网

这里的CreateUninitializedSessionState方法实际就是调用this._store.CreateUninitializedItem(this._rqContext, this._rqId, s_timeout);

我们前面知道this._store这个可以取很多实例的,是SessionStateStoreProviderBase类型,这里我们也已默认的InProcSessionStateStore(继承SessionStateStoreProviderBase)来说说吧,相关方法:

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

现在我们终于明白一个Sessionid对应一个SessionStateStoreData,所以它能区分不同的用户请求,这里的id就是我们前面的this._rqId了。

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

现在我们也总结一下吧,我们的HttpContext的Session属性实际上是一个HttpSessionStateContainer实例(HttpSessionStateContainer继承IHttpSessionState),而它数据成员都是保存在ISessionStateItemCollection实例中,每一次http请求我们都会去获取它的Sessionid,第一次请求sessionid问null,我们没有对应的SessionStateStoreData数据,这时我们在SessionStateModule的 InitStateStoreItem方法调用SessionStateStoreProviderBase的CreateNewStoreData方法来创建一个SessionStateStoreData实例,其中该实例有一个成员变量类型是ISessionStateItemCollection用来保存用户session的数据。同一个用户第二次请求我们能获取到它的sessionid,默认也能获取到SessionStateStoreData实例(session过期则取不到)。一个用户对应一个SessionStateStoreData,每个SessionStateStoreData里面有一个ISessionStateItemCollection实例用来保存用户数据,至于sessionid也就是用户身份的区别依赖于ISessionIDManager的实现。

我们还是简单的来复习一下Session吧:Session的数据时保存在服务器端,并且每个客户端对应不同Session。那么Session究竟是如何保存,如何区分客服端的了?我们还是沿用以前的方法来讲吧,以一个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); } }

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

假设我们的请求路径为http://localhost:18385/WebForm1.aspx?name=majiang

第一次请求数据如下:

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

第二次请求数据了:

这里我们看见在第一次请求的返回头里面有一个ASP.NET_SessionId,在第二次请求过程中这个请求头里面也含有ASP.NET_SessionId,并且它的值刚好是Session.SessionID(我这里用的是asp.net4.5),我们可以猜测这个ASP.NET_SessionId就是用来区分不同的客户端请求。那么这个值是什么时候生成的又是什么时候输出的了?

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

首先我们需要知道我们用到的那个Session具体在什么地方定义的,其实它是定义于HttpContext的Session属性中,我们一般的page也只是调用这个属性而已。

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

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

这两个方法干什么的我就不说了,它们是在什么地方调用的了。如果你开发过asp.net,那么你应该知道在SessionStateModule 类,它是一个IHttpModule的实现者专门用来管理Session的,在这个类中有一个InitModuleFromConfig方法,该方法主要是在该类的Init中调用,如丧我们来看看它的具体实现吧:

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

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

这里主要是设置this._store和 this._idManager 它们两个变量,其中this._store的设置根据Session的存储类型不同设置为不同的实例,这里的存储方式有以下四种

public enum SessionStateMode{ Off, InProc, StateServer, SQLServer, Custom}默认的是SessionStateMode.InProc,所以默认的this._store是一个InProcSessionStateStore实例,而this._idManager默认是一个SessionIDManager实例。这个方法结束后我们的this._store和 this._idManager这两个变量就已经有值了。在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; }

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

在这个方法中有以下3句比较重要

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

第一句获取SessionID,第二句货物SessionStateItem,第三句主要是调用一个CompleteAcquireState方法,而这个方法里面有一句 SessionStateUtility.AddDelayedHttpSessionStateToContext(this._rqContext, this);或则this.InitStateStoreItem(true); 这个方法主要对应一句

http://www.haoz.net●☛█▼▲◐●☛█▼▲◐◐◐◐●☛█▼▲◐豪仕知识网●☛█▼▲豪仕知识网

SessionStateUtility.AddHttpSessionStateToContext(this._rqContext, this._rqSessionState);,在这个类中还有一个方法OnReleaseState里面有这么一句

SessionStateUtility.RemoveHttpSessionStateFromContext(this._rqContext, delayed);

我们首先来可看看SessionStateUtility的AddHttpSessionStateToContext、RemoveHttpSessionStateFromContext方法的实现吧。

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

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句吧,

◐◐◐◐●☛█▼▲豪仕知识网HT●☛█▼▲◐◐◐◐●☛█▼▲

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

默认情况下我们的cookie是可用的,这里的Config.CookieName实际上就是SessionStateSection的CookieName属性

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

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲HtTp://wWW.haoz.net豪仕知识网●●●●●●●●●●●●●●●●●●●●●●●●●●

到这里大家应该知道为什么Http请求和返回关于Session对应Cookie的id是ASP.NET_SessionId了吧。不过大家要注意一点这里的SessionIDManager 在操作cookie做了一些数据验证处理,如果在特殊情况需要自定义验证规则我们可以自己来实现ISessionIDManager接口。这里我们可以看到第一次请求是没有sessionid的,所以sessionStateItem = this.GetSessionStateItem();这句代码不会执行,sessionStateItem默认为true,但是第二次请求时有sessionid这句代码就会执行。GetSessionStateItem()的实现这里我们就忽略了吧,这个方法设置一个SessionStateStoreData的实例this._rqItem ,如果this._rqItem为null则返回false。一般我们的Session都是可读写的。GetSessionStateItem方法主要是调用 this._rqItem = this._store.GetItemExclusive(this._rqContext, this._rqId, out flag2, out span, out this._rqLockId, out this._rqActionFlags);现在我们回到CompleteAcquireState方法中来:

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

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

◐◐◐◐●☛█▼▲豪仕知识网HT●☛█▼▲◐◐◐◐●☛█▼▲

这里是flag默认是false,里面具体判断就不说,InitStateStoreItem方法主要代码:

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

◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲◐◐◐◐●☛█▼▲豪仕知识网HtTp://▲▼▲▼▲

this._rqSessionItems = this._rqItem.Items;

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

HTTP://WWW.haoz.net豪仕知识网采集不好玩哦◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐◐撒旦法师打发斯蒂芬

这里InProcSessionStateStore 的CreateNewStoreData方法实际就是调用SessionStateUtility.CreateLegitStoreData:

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

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

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

这里创建了一个 HttpSessionStateContainer实例。我想大家到这里就应该明白我们的Session实际上就是一个HttpSessionStateContainer实例。

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

好现在我来看Session.SessionID这个是怎么实现的public string SessionID{ get { if (this._id == null) {this._id = this._stateModule.DelayedGetSessionId(); } return this._id; }}

而SessionStateModule的DelayedGetSessionId方法实现如下:

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具体是怎么创建我就不说了吧,知道它是真正创建sessionid的就可以。而session的实际操作都是在ISessionStateItemCollection里面如HttpSessionStateContainer的Add方法:

◐◐◐◐●☛█▼▲豪仕知识网http://www.haOz.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

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

◐◐◐◐●☛█▼▲豪仕知识网███████豪仕知识网HTtp://www.haoZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

而这里的_sessionItems实际上是this._rqItem.Items,本来想忽略_rqItem的创建,看来这个实例比较强啊。

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方法实际就是调用this._store.CreateUninitializedItem(this._rqContext, this._rqId, s_timeout);

◐◐◐◐●☛█▼▲豪仕知识网███████http://www.haOZ.net▼▲▼▲▼▲▼▲▼●●●●●●●▼▲▼▲▼▲

我们前面知道this._store这个可以取很多实例的,是SessionStateStoreProviderBase类型,这里我们也已默认的InProcSessionStateStore(继承SessionStateStoreProviderBase)来说说吧,相关方法:

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

现在我们终于明白一个Sessionid对应一个SessionStateStoreData,所以它能区分不同的用户请求,这里的id就是我们前面的this._rqId了。

现在我们也总结一下吧,我们的HttpContext的Session属性实际上是一个HttpSessionStateContainer实例(HttpSessionStateContainer继承IHttpSessionState),而它数据成员都是保存在ISessionStateItemCollection实例中,每一次http请求我们都会去获取它的Sessionid,第一次请求sessionid问null,我们没有对应的SessionStateStoreData数据,这时我们在SessionStateModule的 InitStateStoreItem方法调用SessionStateStoreProviderBase的CreateNewStoreData方法来创建一个SessionStateStoreData实例,其中该实例有一个成员变量类型是ISessionStateItemCollection用来保存用户session的数据。同一个用户第二次请求我们能获取到它的sessionid,默认也能获取到SessionStateStoreData实例(session过期则取不到)。一个用户对应一个SessionStateStoreData,每个SessionStateStoreData里面有一个ISessionStateItemCollection实例用来保存用户数据,至于sessionid也就是用户身份的区别依赖于ISessionIDManager的实现。

http://www.haoz.net●☛█▼▲◐●☛█▼▲◐◐◐◐●☛█▼▲◐豪仕知识网●☛█▼▲豪仕知识网

关于Asp.net开发中Session是如何实现存储的的内容到此结束,希望对大家有所帮助。豪仕知识网往后会继续推荐Asp.net开发中Session是如何实现存储的相关内容。

相关文章