一、会话状态Session

  Session用于服务器端状态管理,使用Session之后,每个客户端都可以将实际的数据保存在服务器上,对于每个客户端的数据,将会生成一个对应的唯一的key(保存在客户端)。客户端与服务器端就是通过这个key来确认客户端的身份,通常这个key为SessionID。

  一般情况下,SessionID以Cookie的形式保存在浏览器中,在不使用Cookie的情况下,也可以将这个SessionID嵌入到访问网页的URL中。

二、服务器端Session

  在页面对象或者HttpContext对象中,都有一个名为Session的属性,在一次会话中,它们引用的都是同一个对象。

  public HttpSessionState Session { get; }

  Session对象是HttpSessionState类的实例。Session是保存在服务器端的,对每个登录到网站的用户都有一份,是独有的,而其他用户无法共享。

  HttpSessionState来自于HttpModule的SessionStateModule。在每次请求处理过程中,HttpApplication的请求的处理管道中会检查当前请求的处理程序是否实现了接口IRequiresSessionState,如果实现的话,那么SessionStateModule将为这个请求分配HttpSessionState。同时SessionStateModule还负责SessionID的生成、Cookieless会话管理、从外部状态提供程序中检索会话数据以及将数据绑定到请求的调用上下文。

  • 对于一般处理程序,默认情况下没有实现IRequiresSessionState接口。所以如果想要在一般处理程序中使用Session,可以通过实现IRequiresSessionState接口来解决这个问题,这个接口是一个标记接口,并没有定义任何内容。
  • 对于页面处理程序,可以将页面指令@Page的EnableSessionState属性设置为true,以允许页面可以请求会话状态的写入权限。这是默认的设置。还可以将EnableSessionState属性设置为ReadOnly,此时派生的实际页面类将会实现接口IReadOnlySessionState,在这种情况下,页面可以拥有会话状态的只读权限。

  SessionStateModule模块从特定状态提供程序中读取数据。在程序代码中实际上访问的是会话数据在本地内存中的副本,如果其他页面也视图同步访问该会话状态就可能会导致数据冲突。为了避免这种情况,SessionStateModule模块实现了一个读取器/写入器的锁定机制,并对状态值的访问进行排队。对会话状态具有写入权限的页面将保留该会话的写入器锁定,直到请求终止。

  如果页面请求设置一个读取器锁定,同一会话中同时处理的其他请求将无法更新会话状态,但是至少可以进行读取。如果页面请求为会话状态设置一个写入锁,那么所有其他页面都被阻止,无论他们是否要读取或写入内容。例如,如果同时有两段程序视图在同一个Session中写入内容,一段程序必须等到另一段程序完成后才能写入。在AJAX程序设计中,必须注意这种情况的发生。

  来看一个非常有趣的示例:Asp.net设置session后变单线程执行

  新建一个MVC项目,添加一个Controller如下:

   public class HomeController : Controller
{
public ActionResult Index()
{
//Session["User"] = "张三";  //特别注意这行代码 return View();
} public ActionResult Test1()
{
Thread.Sleep(5000);
return Content("长任务Test1完成");
} public ActionResult Test2()
{
return Content("短任务Test2完成");
}
}

  /Home/Index视图代码如下:

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Index</title>
<script src="/Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
$("#btn1").click(function() {
$.ajax({
url: "/Home/Test1",
dataType: "text",
success: function(response) {
$("#div1").html($("#div1").html() + response + "<br/>");
}
}) $.ajax({
url: "/Home/Test2",
dataType: "text",
success: function(response) {
$("#div1").html($("#div1").html() + response + "<br/>");
}
})
})
})
</script> </head>
<body>
<div id="div1" style="width:200px; height:200px; border:1px solid #000;"> </div>
<input type="button" id="btn1" value="开始" />
</body>
</html>

  在刚开始的时候,Index的Session[]那行代码是注释掉的,输出如下:

  

  乍眼一看,这很正常jQuery的AJAX默认是异步执行,那个先执行完就哪个先显示,没问题。

  下面,启用那行被注释掉的Session代码,输入如下:

  

  这次点击按钮没有反应,虽然jQuery的AJAX是已经发送出去了,但是Asp.net必须要等到第一个请求执行完毕之后,第二个请求才开始执行。这从google浏览器的请求信息可以看到,两个请求几乎是同时发出去的,是Asp.net使用了Session导致的问题:

  

  特别说明:只有写Session时,Asp.net才会阻塞请求,但是只要你访问过写Session的页面,比如是用Session登录的系统之后的操作(直到Session失效都一直锁定,当然只是SessionID相同的情况)。都会存在这个问题。光读Session不会出现这种情况。

  这个问题在开发一些并发的Asp.net功能时需要注意,例如进度条。

  在MVC中有一个办法可以解决这个问题,在MVC中,可以为本Controller增加以下特性,但是本Controller都不能修改Session了,只能读取。

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]

  对于WebForm来说是在aspx顶部的Page后面加上(仅仅加载那个阻塞页面):

EnableSessionState="ReadOnly"

三、客户端的SessionID

  对于会话的每个客户端来说,需要在浏览器中保存一个会话的标识,以便在后继的请求中区分不同的会话,这个标识我们成为SessionID。

  SessionID是由SessionStateModule创建的,在创建一个新的SessionID之后,SessionStateModule将会触发Session_Start事件,我们可以在Global.asax中处理这个事件。

        void Session_Start(object sender, EventArgs e)
{
// 在新会话启动时运行的代码
}

  如果会话超时或被放弃,下次访问应用程序时,SessionID并不会发生改变。即使会话状态过期,会话SessionID也能持续到浏览器会话结束。也就是说,只要浏览器实例相同,就始终使用同一个会话SessionID表示多个会话。

  Session_End事件标志着会话的结束,并用于执行终止该会话所需的所有清除代码。但请注意,只有InProc模式支持该事件,也就是说,只有将会话数据存储在Asp.net辅助进程中时才支持该事件。对于要引发Session_End事件来说,必须首先存在会话状态,这意味着必须在改会话状态中存储一些数据,并且必须至少完成一个请求,才会触发这个事件。

        void Session_End(object sender, EventArgs e)
{
// 在会话结束时运行的代码。
// 注意: 只有在 Web.config 文件中的 sessionstate 模式设置为
// InProc 时,才会引发 Session_End 事件。如果会话模式设置为 StateServer
// 或 SQLServer,则不会引发该事件。
}

  InProc是最常用的也是Asp.net默认的模式,添加到缓存中的会话状态被赋予一个滑动过期策略。服务器将会进行一个倒计时,当倒计时到0的时候,意味着会话过期。滑动过期时间表示如果在一定时间内没有使用,将被删除。在过期之前,处理任何请求的时候,过期时间都将重新设置为会话的过期时间。

  例如,如果Session的过期时间是20分钟,那么在过期之前,每次请求都会导致这个事件被重新设置为20分钟。

  过期的会话数据将自动被删除。状态会话模块也包含一个删除会话的回调函数。当会话数据被删除的时候,将自动调用删除函数,然后删除函数将引发Session_End事件。但是,如果应用程序没有通过InProc模式来进行会话管理,将永远不会引发结束事件。
  SessionID由URL允许的120位字符串组成。默认情况下,SessionID以Cookie的形式发送到客户端保存起来,如果没有设置Cookie的Expires过期时间属性,那么SessionID在关闭浏览器的时候就失效了。

  SessionID字符串被发送到浏览器,然后通过以下两种方式之一返回服务器应用程序:

  1. 使用Cookie。
  2. 经过修改的URL。

  配置会话设置使用sessionState元素的Cookieless特性:

<sessionState cookieless="true" />

  cookieless false表示使用Cookie,true表示使用URL。如果使用了URL则路径如:

  http://localhost:9090/website/(S(qifjgkvmcnfu8j93ks74ieu7))/SessionID.aspx

四、Session的过期问题

  关于Asp.net会话管理,重要的一点是,仅当将第一个项目添加到内存词典中时,会话状态对象的生命周期才开始。如:仅在执行如下代码片段后,才可以认为Asp.net会话开始。

Session["XXX"] = "XXX";

  Session词典通常包含Object类型,要向后读取数据,需要将返回的值转换为更具体的类型。

string data = Session["XXX"].ToString();

  当将数据保存到Session中时,值会加载到HttpSessionState类包含的特制的词典类中。完成当前处理的请求时,会将词典的内容加载到状态提供程序中。
如果会话超时或被放弃,下次访问无状态应用程序时,其会话ID不会变,即使会话状态过期,SessionID也能持续到浏览器会话结束。也就是说,只要浏览器实例相同,就始终使用同一个会话ID表示多个会话。

  Session_OnEnd事件标志着会话的结束,并用于执行终止该会话所需的所有清除代码。但要注意,只有InProc模式支持该事件,也就是说,只有将会话数据存储在Asp.net辅助进程中时才支持该事件。对于要引发的Session_OnEnd事件来说,必须首先存在会话状态,这意味着必须在该会话状态中存储一些数据,并且必须至少完成一个请求。

五、sessionState配置节

  sessionState配置节主要用于配置Session方面的信息,部分节点如下:

配置节点 说明
mode

mode 取值如下,默认为 InProc 。

Custom :会话状态正在使用自定义数据存储来存储会话状态信息。

InProc :会话状态正在处理 ASP.NET 辅助进程。

Off :会话状态被禁用。

SQLServer :会话状态正在使用进程外 SQL Server 数据库存储状态信息。

StateServer :  会话状态将使用进程外 ASP.NET 状态服务来存储状态信息。

cookieName

指定存储会话标识符的 Cookie 的名称(就是客户端的Key),默认值为 "ASP.NET_SessionId"。

cookieless

当网站用到AJAX时,该属性仅能够使用UseCookies。

AutoDetect :Asp.net自动判断,如果浏览器支持Cookie,则使用 Cookie 来传输;否则,使用Uri传输。 如果浏览器支持Cookie,但禁用了Cookie,则仍然使用 Cookie。 
UseCookies :无论浏览器或设备是否支持 Cookie,都使用 Cookie 来保留用户数据。
UseDeviceProfile :ASP.NET 根据 HttpBrowserCapabilities自动判断。 如果 HttpBrowserCapabilities 设置指示浏览器或设备支持 Cookie,将使用 Cookie;否则,将在查询字符串中使用一个标识符。
UseUri :无论浏览器或设备是否支持Cookie,都使用UseUri来传输SessionID

customProvider

自定义会话状态提供程序的名称

timeout

指定一个会话多长时间空闲会失效。 对于进程内和状态服务器模式,timeout 特性不能设置为大于 525,600 分钟(1 年)的值。

compressionEnabled

进程外的Session是否先压缩后传输。如是否压缩后再发送到SQLServer

  http://msdn.microsoft.com/zh-cn/library/h6bb9cz9.aspx

  StateServer的Session Mode模式的StateServer会将Session数据存在于aspnet_state.exe里面。与w3wp.exe/aspnet_wp.exe进程相互独立。如果存放于InProc,则是存放于Asp.net进程内。

六、HttpSessionState类

属性 说明
CodePage 获取或设置当前会话的字符集标识符
Contents 获取对当前会话状态对象的引用
CookieMode 获取一个值,该值指示是否为无 Cookie 会话配置应用程序
Count 获取会话状态集合中的项数
IsCookieless 获取一个值,该值指示会话 ID 是嵌入在 URL 中还是存储在 HTTP Cookie 中。 如果会话嵌入在 URL 中,则为 true;否则,为 false
IsNewSession 获取一个值,该值指示会话是否是与当前请求一起创建的。  如果会话是与当前请求一起创建的,则为 true;否则,为 false
IsReadOnly 获取一个值,该值指示会话是否为只读
IsSynchronized 获取一个值,该值指示对会话状态值的集合的访问是否是同步(线程安全)的
Item 获取或设置个别会话值Session[]
Keys 获取存储在会话状态集合中所有值的键的集合
LCID 获取或设置当前会话的区域设置标识符 (LCID)
Mode 获取当前会话状态模式
SessionID 获取会话的唯一标识符
StaticObjects 获取由 ASP.NET 应用程序文件 Global.asax 中的 <object Runat="Server" Scope="Session"/> 标记声明的对象的集合
SyncRoot 获取一个对象,该对象可用于同步对会话状态值的集合的访问
Timeout  获取并设置在会话状态提供程序终止会话之前各请求之间所允许的时间(以分钟为单位)

方法:

方法 说明
Abandon 取消当前会话
Add 向会话状态集合添加一个新项
Clear 从会话状态集合中移除所有的键和值
CopyTo 将会话状态值的集合复制到一维数组中(从数组的指定索引处开始)
GetEnumerator 返回一个枚举数,可用来读取当前会话中所有会话状态的变量名称
Remove  删除会话状态集合中的项
RemoveAll 从会话状态集合中移除所有的键和值
RemoveAt 删除会话状态集合中指定索引处的项

  一旦调用 HttpSessionState.Abandon方法,当前会话不再有效,同时会启动新的会话。Abandon 使 SessionStateModule.End 事件被引发。发送下一次请求后将引发新的 SessionStateModule.Start 事件。如果要用Session.Abandon();最好放在一个独立的页面。

代码示例:

        protected void Page_Load(object sender, EventArgs e)
{
Session.Add("username","admin");
Session.Add("password","123456"); Response.Write(Session.Count); //输出2
Response.Write(Session.IsCookieless); //输出 False 表示是嵌入在cookie里
Response.Write(Session.CodePage); //输出 65001
Response.Write(Session.Contents["username"]); //输出 username
Response.Write("<br/>");
Response.Write(Session.CookieMode); //UserCookies
Response.Write(Session.IsNewSession); //True
Response.Write(Session.IsReadOnly); //False
Response.Write(Session.IsSynchronized); //False foreach (string str in Session.Keys)
{
Response.Write(str + ":" + Session[str]); //username:admin password:123456
} Response.Write("<br/>");
Response.Write(Session.LCID); //2052
Response.Write(Session.Mode); //InProc
Response.Write(Session.SessionID); //udtst2kwyltquymd40alduyw Response.Write("<br/>");
Response.Write(Session.StaticObjects.Count); //0
Response.Write(Session.SyncRoot); //
Response.Write(Session.Timeout); //20 string[] strArr = new string[Session.Count];
Session.CopyTo(strArr,0);
foreach (string str in strArr)
{
Response.Write(str); //输出 username password 输出由key组成的字符串数组
} Session.Remove("password");
Response.Write(Session.Count); //输出1 可以看到少了一个
Session.RemoveAt(0); //按索引号删除一个Session对象
Response.Write(Session.Count); //输出0 可以看到又少了一个
Session.Add("one","刘备");
Session.Abandon();
Response.Write(Session["one"]);
Response.Write("<a href='/new.aspx'>新页面</a>"); //由于调用了ababdon()方法,因此点击此页面过去,将获取不到Session["one"]
}

  new.aspx后台代码:

        protected void Page_Load(object sender, EventArgs e)
{
Response.Write(Session["one"]);  //虽然输出cookie中的值,但是不会输出任何值
}

.net学习笔记----会话状态Session的更多相关文章

  1. Laravel学习笔记之Session源码解析(上)

    说明:本文主要通过学习Laravel的session源码学习Laravel是如何设计session的,将自己的学习心得分享出来,希望对别人有所帮助.Laravel在web middleware中定义了 ...

  2. Laravel学习笔记之Session源码解析(下)

    说明:在中篇中学习了session的CRUD增删改查操作,本篇主要学习关闭session的相关源码.实际上,在Laravel5.3中关闭session主要包括两个过程:保存当前URL到session介 ...

  3. Laravel学习笔记之Session源码解析(中)

    说明:在上篇中学习了session的启动过程,主要分为两步,一是session的实例化,即\Illuminate\Session\Store的实例化:二是从session存储介质redis中读取id ...

  4. Web安全测试学习笔记(Cookie&Session)

    一,Session:含义:有始有终的一系列动作\消息1, 隐含了“面向连接” 和“保持状态”两种含义2, 一种用来在客户端与服务器之间保持状态的解决方案3, 也指这种解决方案的存储结构“把××保存在s ...

  5. EMQ学习笔记---Clean Session和Retained Message

    MQTT会话(Clean Session)MQTT客户端向服务器发起CONNECT请求时,可以通过’Clean Session’标志设置会话.‘Clean Session’设置为0,表示创建一个持久会 ...

  6. python学习笔记(session)

    昨天提到想加入cookies 测试登录后的接口 尝试了下 只要用 session方法即可 代码如下 #!/usr/bin/env python # -*- coding: utf_8 -*- impo ...

  7. 1.6(学习笔记)Session

    一. Session简介 Session是用于解决HTTP无状态问题,HTTP协议本身是没有状态的, 就类似一个没有记性的商人,每次只交易当前的货物,交易完后就忘记了 以前的交易历史.我们和商人交易时 ...

  8. Tensorflow学习笔记2:About Session, Graph, Operation and Tensor

    简介 上一篇笔记:Tensorflow学习笔记1:Get Started 我们谈到Tensorflow是基于图(Graph)的计算系统.而图的节点则是由操作(Operation)来构成的,而图的各个节 ...

  9. [原创]java WEB学习笔记94:Hibernate学习之路---session 的管理,Session 对象的生命周期与本地线程绑定

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

随机推荐

  1. POJ2823Sliding Window

    Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 49919   Accepted: 14391 ...

  2. .net mvc4 利用 kindeditor 上传本地图片

    http://blog.csdn.net/ycwol/article/details/41824371?utm_source=tuicool&utm_medium=referral 最近在用k ...

  3. app工程构成

    1)工程配置文件: 2)源代码: 3)资源文件.

  4. centos命令

     alt + z 打开终端(自定义命令)  su 切换到root

  5. jQuery Uploadify在ASP.NET MVC中的使用

    感谢http://www.cnblogs.com/libingql/archive/2012/09/11/2681007.html 除此之外,给大家推荐一个: http://gallery.kissy ...

  6. Serenity框架官方文档翻译(1-2开始、安装和界面)

    1.开始 最好的和最快速地上手Serenity的方法是使用SERENE,它是一个示例应用程序模板. 您有2个选项来安装SERENE 模板到您的Visual Studio: 从Visual Studio ...

  7. SQL例题合集

    1. 查询Student表中的所有记录的Sname.Ssex和Class列. Select sname,ssex,class from student; 2. 查询教师所有的单位即不重复的Depart ...

  8. 《Hadoop基础教程》之初识Hadoop

    Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不适用我们的项目,但是我会继续研究下去,技多不压身. <Hadoop基础教程> ...

  9. 简单实现Tab切换(带框架)

    <script type="text/javascript"> $(function () { //加载时添加的标签卡 if ('<%=Request[" ...

  10. 粒子滤波particle filter和目标跟踪

    粒子滤波用于跟踪,参考:http://www.cnblogs.com/tornadomeet/archive/2012/03/18/2404817.html http://blog.csdn.net/ ...