ASP.NET的Session 详解

来源:互联网 发布:淘宝网购物男装外套 编辑:程序博客网 时间:2024/05/01 20:46

Session又称为会话状况,是Web体系中最常用的状况,用于保护和当前浏览器实例相干的一些信息。举个例子来说,我们可以把已登录用户的用户名放在Session中,如许就能经由过程断定Session中的某个Key来断定用户是否登录,若是登录的话用户名又是几许。

我们知 道,Session对于每一个客户端(或者说浏览器实例)是“人手一份”,用户初次与Web办事器建树连接的时辰,办事器会给用户分发一个 SessionID作为标识。SessionID是一个由24个字符构成的随机字符串。用户每次提交页面,浏览器都邑把这个SessionID包含在 HTTP头中提交给Web办事器,如许Web办事器就能区分当前恳求页面的是哪一个客户端。那么,ASP.NET 2.0供给了哪些存储SessionID的模式呢:

·      Cookie(默认)。若是客户端禁止了Cookie的应用,Session也将失效。

·      URL。Cookie是否开启不影响Session应用,毛病是不克不及再应用绝对链接了。

前面说了SessionID可以存储在客户端的Cookie或者URL中,那么Session真正的内容存储在哪里呢?ASP.NET 2.0对于Session内容的存储也供给了多种模式。

·      InProc(默认)。Session存储在IIS过程中(Web办事器内存)。

·      StateServer。Session存储在自力的Windows办事过程中(可以不是Web办事器)。

·      SqlServer。Session存储在SqlServer数据库的表中(SqlServer办事器)。

固然 InProc模式的Session直接存储在Web办事器IIS过程中,速度斗劲快,然则每次从头启动IIS都邑导致Session丧失。哄骗后两种模式,我们就完全可以把Session从Web办事器中自力出来,从而减轻Web办事器的压力,同时削减Session丧失的概率。

是以,SessionID存储在客户端(可所以Cookie或者URL),其他都存储在办事端(可所以IIS过程、自力的Windows办事过程或者SQL Server数据库中)。

12.3.2  Session的应用

让我们先来实践一下如何应用Session,进而答复第二个题目:Session存储的类型限制。Session不须要进行任何设备就可以应用(默认是InProc模式并且依附Cookie)。起首,在页面上建树两个按钮。

在btn_WriteSession按钮的Click事务处理惩罚办法中,写入两个Session,一个是简单的字符串,别的一个是自定义的类。

protected void btn_WriteSession_Click(object sender, EventArgs e){    Session["SimpleString"] = "编程康乐";    MyUser user = new MyUser();    user.sUserName = "小朱";   user.iAage = 24;    Session["CustomClass"] = user;}

Session的应用很是简单,直接对某个Key的Session进行赋值即可。自定义类MyUser如下:

class MyUser{    public string sUserName;    public int iAage;    public override string ToString()    {    return string.Format("姓名:{0},春秋:{1}", sUserName, iAage);    }}


在这里,我们覆写了ToString()办法直接返回实例的一些信息。然后,双击btn_ReadSession按钮来实现从Session中读取数据的代码:

protected void btn_ReadSession_Click(object sender, EventArgs e){    if (Session["SimpleString"]==null)    {       Response.Write("读取简单字符串失败");    }    else    {        string s=Session["SimpleString"].ToString();        Response.Write(s + "");    }    if (Session["CustomClass"]==null)   {        Response.Write("读取简单自定义类失败");    }    else    {        MyUser user=Session["CustomClass"] as MyUser;        Response.Write(user.ToString()+"");    }}

 

 

在每次读取Session的值以前请务必先断定Session是否为空,不然很有可能呈现“未将对象引用设置到对象的实例”的异常。我们看到,从Session 中读出的数据都是object类型的,我们须要进行类型转化后才干应用。打开页面,先单击写入Session按钮,再单击读取Session按钮,页面输出如    图12-1所示。


12.3.3  把Session存储在自力的过程中

由此看来,Session能存储随便率性对象,是如许吗?如今得出这个结论还太早了一点,因为我们并没有实践过StateServer和SqlServer模式的Session。要把Session存储在Windows办事过程中须要进行以下几个步调。


n  第1步是打开状况办事。依次打开“把握面板”→“经管对象”→“办事”号令,找到ASP.NET状况办事一项,右键单击办事选择启动,如图12-2所示。


图12-2  启动ASP.NET状况办事


n  若是你正式决意应用状况办事存储Session前,别忘怀批改办事为自启动(在操纵体系重启后办事能本身启动)以免忘怀启动办事而造成网站Session不克不及应用,如图12-3所示,双击办事把办事的启动类型设置为主动。


图12-3  批改办事启动类型为主动


办事正常启动后可以调查任务经管器的过程页,此中的aspnet_state.exe过程就是状况办事过程,如图12-4所示。


图12-4  调查任务经管器的过程页


n  第2步,在system.web节点中参加:


stateNetworkTimeout="20">


n  stateConnectionString默示状况办事器的通信地址(IP:办事端标语)。因为我们如今在本机进行测试,这里设置本钱机地址127.0.0.1。状况办事默认的监听端口为42422。当然,您也可以经由过程批改注册表来批改状况办事的端标语。


n  1.在运行中输入regedit启动注册表编辑器。


n  2.依次打开HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesaspnet_stateParameters节点,双击Port选项,如图12-5所示。


选择基数为十进制,然后输入一个端标语即可。stateNetworkTimeout属性默示从状况办事器恳求Session数据最长的时候,默认为10秒,若是收集连接不是很好,请把这个数字恰当设置得大一点。


n  第3步打开页面,单击“写入Session”按钮,体系会报错,如图12-6所示。


        图12-5  批改状况办事端标语            图12-6  向StateServer默认的Session中写入自定义类失足


提示已经说得很清楚了,只有把对象标注为可序列化后才干在办事中进行存储。什么是序列化呢?序列化是指将对象实例的状况存储到存储媒体的过程。在此过程中,先将对象的公共字段和私有字段以及类的名称转换为字节俭,然后再把字节俭写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全雷同的副本。要使一个类可序列化,最简单的办法是应用 Serializable 属性对它进行标识表记标帜。

[Serializable]class MyUser{    public string sUserName;    public int iAage;    public override string ToString()    {        return string.Format("姓名:{0},春秋:{1}", sUserName, iAage);    }}

n  第4步如今从头打开页面进行测试,获得的成果和应用InProc模式是一样的。


12.3.4  把Session存储在数据库中

要把Session存储在SqlServer中,根蒂根基上也是这么几个步调。


n  1.在号令行窗口输入cmd并在号令行中运行如下号令。


C:WINDOWSMicrosoft.NETFrameworkv2.0.50727aspnet_regsql.exe -S .SqlExpress -E –ssadd


此中 C:Windows用你本身Windows的目登科代,v2.0.50727用你安装的2.0框架的版本号庖代。-S指定SqlServer办事器地址,-E默示采取信赖连接,-ssadd默示为SqlServer办事器添加状况办事的支撑。操纵停止后,你可以应用IDE的办事器资料经管器连接 SqlExpress数据库,可以看到多了一个ASPState数据库,然则新鲜的是数据库中没有任何表却有很多存储过程,如图12-7所示。


其实,所有Session的数据都存放在了tempdb数据库内,如图12-8所示。

         

    图12-7  应用办事器资料经管器浏览ASPState数据库      图12-8  存放Session数据的tempdb数据库


其实,aspnet_regsql.exe有一个-sstype参数可以用来指定Session的内容和操纵的存储过程存放的表。因为篇幅关系,在这里就不具体介绍了,读者可以应用aspnet_regsql.exe/?来浏览法度具体的应用体式格式。


n  2.打开Web.config文件,批改前面建树的sessionState节点。

为sqlConnectionString 属性指定以前一向用的连接字符串,独一不合的是不须要再指定命据表的名字了。sqlCommandTimeout属性默示容许履行Sql号令最长的时候,默认为30秒,可以按照本身的须要恰当调剂这个数字。最后,从头打开页面进行测试,获得的成果和应用InProc模式是一样的(同样你须要确保在自定义类前标注了[Serializable]),不过我们能感觉速度有些慢了,毕竟成果数据是从数据库中进行读取或保存的,并且在应用前还须要经过序列化和反序列化操纵。

是以Session能存储的类型为: 对于InProc模式是一切类型,而对于StateServer和SqlServer模式是一切可以序列化的类型。


12.3.5  Session的应用局限与大小限制

那么, 会话状况应用的局限和大小限制又是怎么样的呢?我们可以解析一下图12-8,体系应用两个表来存储Session的状况。此中有一个 ASPStateTempApplication表,用来存储Session地点的应用法度,必然程度上反应了Session是不克不及跨应用法度的。举例来说,我们在策画机上建树了两个网站,同时都应用Session[“UserName”]来保存登录的用户名,一个网站的用户登录后,另一个网站直接接见 Session[“UserName”]是取不到任何值的。那么,Session是否可以跨用户呢?经由过程前面的解析我们知道,必然是不可的, Session经由过程SessionID来区分用户,一般来说SessionID是不成能呈现反复的现象,也就是说Session一般是不会“串号”的。既然页面每次提交的时辰都邑附加被骗前用户的SessionID,那么Session应当是可以跨页面的,也就是说一个网站中所有的页面都应用同一份 Session。你可以本身来做个实验,请读者打开刚才那个页面,然后按Ctrl+N组合键再打开第二个同样的页面,单击第一个页面中的“写入 Session”按钮,单击第二个页面中的“读取Session”按钮,可以发明Session的值被正确读出了。第三个题目的答案有了。

·      Session状况应用的局限:应用同一个客户端(浏览器实例)接见同一个应用法度的所有页面。


我们再来做一个实验,看看Session的容量有多大,在测试以前请批改Web.config,把Session设置为StateServer模式。然后,把写入Session的代码批改成如下(别忘怀using System.Data.SqlCient):

DataSet ds = new DataSet();using (SqlConnection conn = new SqlConnection(@"server=(local)SQLEXPRESS;database=Forum;Trusted_Connection=True")){    SqlDataAdapter da = new SqlDataAdapter(" * tbUser; * tbBoard;* tbTopic;", conn);    da.Fill(ds);}ArrayList al = new ArrayList();for(int i = 0;i<10000000;i++)   al.Add(ds);Session["LargeData"] = al;




我们把包含三个表的DataSet反复参加ArrayList中1000万次。因为这些表几乎每个表只有几笔记录,如许可以模仿大数据量的景象。启动页面,单击“写入Session”按钮后可以发明,Windows办事过程一会儿占用了多达70MB的内存,如图12-9所示。


图12-9  把多量数据存放到Session中


Session 对于网站和用户是自力的,试想一下,若是办事器上有两个网站,每个网站的在耳目数是100人,那么占用内存就要14G。是不是很可骇的数字?是以,固然 Session的大小没有限制,然则我们切切不克不及滥用Session。笔者推荐你在Session中存储少于100K的数据。


·      若是你应用InProc模式的Session,存储过多的数据会导致IIS过程被收受接管,激发Session络续丧失。

·      若是你应用StateServer存储Session,那么数据在存入Session以前须要进行序列化,序列化会消费多量的CPU资料。

·      若是你应用SqlServer模式的Session,数据不单要序列化并且还是存储在磁盘上,更不合适存储多量数据。


12.3.6  Session的生命周期

在懂得了Session中存储的数据无大小限制后,我们可能要更多地关怀Session的生命周期了。我们已经知道,Session是在用户第一次接见网站的时辰创建的,那么Session是什么时辰烧毁的呢?Session应用一种腻滑超时的技巧来把握何时烧毁Session。默认景象下,Session 的超不时候(Timeout)是20分钟,用户对峙连气儿20分钟不接见网站,则Session被收回,若是在这20分钟内用户又接见了一次页面,那么20 分钟就从头计时了,也就是说,这个超时是连气儿不接见的超不时候,而不是第一次接见后20分钟必过期。这个超不时候同样也可以经由过程调剂Web.config 文件进行批改:

当然你也可以在法度中进行设置:

Session.Timeout = "30";

一旦Session超时,Session中的数据将被收受接管,若是再应用Session体系,将给你分派一个新的SessionID。本节一开端我们就介绍了可以在URL中存储SessionID,如今请你设备Web.config文件,设置Session超不时候为1分钟,SessionID在URl中存放。打开页面后单击“写入Session”按钮,过1分钟再次单击按钮并调查SessionID是否变更。

如图12-10所示,SessionID的确产生了变更。


图12-10  超时后SessionID产生变更


不过,你可别太信赖Session的Timeout属性,若是你把它设置为24小时,则很难信赖24小时之后用户的Session还在。Session是否存在,不仅仅依附于Timeout属性,以下的景象都可能引起Session丧失(所谓丧失就是在超时以前本来的Session无效)。


·      bin目次中的文件被改写。asp.net有一种机制,为了包管dll从头编译之后,体系正常运行,它会从头启动一次网站过程,这时就会导致 Session丧失,所以若是有access数据库位于bin目次,或者有其他文件被体系改写,就会导致Session丧失。

·      SessionID丧失或者无效。若是你在URL中存储SessionID,然则应用了绝对地址重定向网站导致URL中的SessionID丧失,那么本来的Session将失效。若是你在Cookie中存储SessionID,那么客户端禁用Cookie或者Cookie达到了IE中Cookie数量的限制(每个域20个),那么Session将无效。

·      若是应用InProc的Session,那么IIS重启将会丧失Session。同理,若是应用StateServer的Session,办事看从头启动Session也会丧失。

一般来说,若是在IIS中存储Session并且Session的Timeout设置得斗劲长,再加上Session中存储多量的数据,很是轻易产生Session丧失的题目。

最后, Session的安然性怎么样呢?我们知道,Session中只有SessionID是存储在客户端的,并且在页面每次提交的过程中参加HTTP头发送给办事器。SessionID只是一个辨认符,没有任何内容,真正的内容是存储在办事器上的。总的来说安然性还是可以的,不过笔者建议你不要应用 cookieless和SqlServer模式的Session。把SessionID露出在URL中,把内容存储在数据库中可能会产生进击隐患。


12.3.7  遍历与烧毁Session

Session固然很便利,然则要用好Session还须要本身络续实践,按照本身网站的特点灵活应用各类模式的Session。关于应用法度接见Session,笔者还想补充两点。

·      如何遍历当前的Session凑集。

System.Collections.IEnumerator SessionEnum = Session.Keys.GetEnumerator();while (SessionEnum.MoveNext()){    Response.Write(Session[SessionEnum.Current.ToString()].ToString() + "");}

对于我们这个例子,输出和图12-1一样。若是你仅仅为了把守Session,也可以经由过程trace来获得具体信息。在Web.config的system.Web节点中添加:

打开页面后单击“写入Session”按钮,页面显示如图12-11所示。


图12-11  应用trace调查会话状况


·      如何立即让Session失效。比如用户退出体系后,Session中保存的所稀有据全部失效,可以应用以下代码来让Session失效。

Session.Abandon();

12.3.8  Session的常见题目与总结

Session的根蒂根基常识就介绍到这里,如今再回头看第一节中的几个题目,你是否都能答复了呢?为了强化大师的概念,笔者就三种模式的Session进行了一个斗劲(假设都应用Cookie来存储SessionID)。

表12.1  三种模式的Session斗劲

 InProc

 StateServer

 SQLServer

 

存储物理地位

 IIS过程(内存)

 Windows办事过程(内存)

 SQLServer数据库(磁盘)

 

存储类型限制

 无穷制

 可以序列化的类型

 可以序列化的类型

 存储大小限制

 无穷制

 

应用局限

 当前恳求高低文,对于每个用户自力

 生命周期

 第一次接见网站的时辰创建Session超时后烧毁

 长处

 机能斗劲高

 Session不依附Web办事器,不轻易丧失

 毛病

 轻易丧失

 序列化与反序列化消费CPU资料

 序列化与反序列化消费CPU资料,从磁盘读取Session斗劲慢

 应用原则

 不要存放多量数据

 

在应用Session的过程中你可能还会碰到很多新鲜的题目,停止本节之前笔者列出了几条常见的FAQ,供大师参考:

·      为什么每次恳求的SessionID都不雷同?

n  可能是没有在Session里面保存任何信息引起的,即法度中任何处所都没有应用Session。只有在Session中保存了内容后,Session才会和浏览器进行接洽关系,此时的SessionID将不会再变更。

·      为什么当我设置cookieless为true后,在重定向的时辰会丧失Session?

n  当应用cookieless时,你必须应用相对路径调换法度中的绝对路径,若是应用绝对路径,ASP.NET将无法在URL中保存SessionID。

·      有办法知道应用法度的Session在运行时占用了几许内存吗?

n 没有办法,你可以经由过程察IIS过程(InProc模式)或者aspnet_state过程(StateServer模式)大致估计。

·      有没有可能知道全部网站应用Session的用户列表?

n  对于InProc模式和StateServer模式很难,对于SqlServer模式你可以查询存储Session的表进行测验测验。

·      当页面中设了frameset,发明在每个frame中显示页面的SessionID在第一次恳求时都不雷同,为什么?

n  原因是你的frameset是放在一个HTML页面上而不是ASPX页面。在一般景象下,若是frameset是aspx页面,当你恳求页面时,它起首将恳求发送到Web办事器,此时已经获得了SessionID,接着浏览器会分别恳求Frame中的其他页面,如许所有页面的SessionID就是一样的,就是FrameSet页面的SessionID。然而若是你应用HTML页面做FrameSet页面,第一个恳求将是HTML页面,当该页面从办事器上返回时并没有任何Session产生,接着浏览器会恳求Frame里面的页面,如许,这些页面都邑产生本身的SessionID,所以在这种景象下就可能呈现这种题目。当你从头刷新页面时,SessionID就会一样,并且是最后一个恳求页面的SessionID。

0 0