什么是状态
要说状态管理机制,得先来说说 “状态” 是个什么玩意儿。怎么理解这个状态?这里举个例子:当你手机快没电的时候,你会发现这个手机的电源指示灯一亮一灭,这其实就是告诉你当前手机的状态变成了 “电量低” 。你一看见这个状态,就知道该充电了。换言之,状态就一堆信息,当你读懂这部分信息的时候,就会执行对应的操作。
再来举个例子,当你要发微博的时候,你得先登录吧? 不登录能不能发微博呢?这个答案显示是否定的。那为什么要登录呢?因为登录之后,才能知道当前这条微博是谁写的。那为什么登录之后,就知道是谁写的了呢?服务器又没和你见过面,凭什么能确定这条微博是你发的呢?那是因为你的成功登录,相当于手机电源指示灯由正常变成一亮一灭,也就是说有了一个状态,服务器看到这个状态就明白这条微博是你发的了。
明白了状态,再来说说状态管理
微博是通过http协议把数据在你家和服务器之间进行点对点传送的,服务器要想知道你的状态就必须通过http协议。可惜,不巧的是HTTP是个无状态的协议。也就是说就算你成功登录了,Http协议也没法记住这个状态,这样下次你和服务器进行通信的时候,服务器仍旧会把你当成陌生人,相当于手机没有电源指示灯(那自然就看不出是否没电了)。
于是就有了下文中要说的各种状态管理机制(这里所罗列的只是本人在开发中所用到过的,可能并不完整)。
首先来看客户端的几种方式
类别 | 大小限制 | 生命周期 | 与会话 (Session)相关 | 保存的位置 | 是否序列化 | 适用情况 | 注意 |
---|---|---|---|---|---|---|---|
可持久化 Cookie | 4K(大多数浏览器) | 在指定时间内持久化保存 | 否,但是特定于单个用户 | 客户端硬盘 | 是 | 当你希望在客户端保存少量数据且不是很在意安全性的时候 | 不同的电脑不能共享,安全性低 |
会话 Cookie | 4K(大多数浏览器) | 会话生命周期 | 是,同时特定于单个用户 | 客户端硬盘 | 是 | ||
ViewState | 小量,简单数据类型 | 一个Web页面的生命周期 | 否,特定于单个页面 | 客户端页面 | 是 | Webform中用于维护同一个页面的状态,如Postb | ack|
隐藏域 | 小量,简单数据类型 | 一个Web页面的生命周期 | 否,特定于单个页面 | 客户端页面 | 是 |
服务器端状态管理
类别 | 大小限制 | 生命周期 | 与会话 (Session)相关 | 保存的位置 | 是否序列化 | 适用情况 | 注意 |
---|---|---|---|---|---|---|---|
Application | 无限制 | Web应用程序生命周期 | 否,所有Web会话共享 | Web应用程序的内存 | 否 | 当需要被不同的会话共享,且不经常变化的数据 | 1. 数据太多的时候,会迅速耗尽服务器内存。 2. 多台web服务器之间不能共享 application。 3. 并发时需要手动加锁。 4. 服务器当机,所有状态丢失。 |
Cache | 无限制 | 可以手动设置缓存时间及相关属性,当在系统内存吃紧的时候会根据这些属性对Cache进行清理 | 否,所有Web会话共享 | Web应用程序的内存 | 否 | ||
Session [InProc] | 小量,简单数据类型 | 用户的活动时间+一段延迟(一般为20分钟) | 是,特定于单个用户会话 | Web应用程序的内存 | 否 | 同个会话不同页面间有传值需求、数据生命周期短、特定于某一个会话。 | 由于存放在Web应用程序的内存中,因此不同的web服务器无法共享状态。 |
Session [StateServer] | 小量,简单数据类型 | 用户的活动时间+一段延迟(一般为20分钟) | 是,特定于单个用户会话 | Asp.net状态管理进程 | 是 | 多台web服务器 | 可以共享状态|
Session [SqlServer] | 小量,简单数据类型 | 用户的活动时间+一段延迟(一般为20分钟) | 是,特定于单个用户会话 | Sql Server | 是 | 多台web服务器可以共享状态 |
基本操作
1. Application
继承自 HttpApplicationState 类,其实例在客户端第一次请求 Web 应用程序时创建。
添加缓存
Application["msg"] = "welcome"; //如果没有msg缓存,则创建一个新的,否则修改原来的。key 不区分大小写 Application.Add("msg","welcome");//2种方式效果一样
因为Application中存储的是没有序列化的对象,所以当保存的是一个引用类型的实例,比如一个数组,后续往数组中加入一个值后,则Application中的值也会发生相应的变化。
读取
string str = Application["msg"] as string;
修改
Application["msg"] = "123"; Application.Set("msg","123");
删除
Application.Remove("msg"); Application.RemoveAll(); Application.Clear();//和RemoveAll完全一样
2. Cache (System.Web.Caching)
添加
Cache["msg"]="welcome"; //如果已经存在则覆盖,否则创建,key 区分大小写 //Add 方式会返回新添加的对象,如果已经存在,则不覆盖。 Cache.Add("msg", "welcome", null, Cache.NoAbsoluteExpiraion, Cache.NoSlidingExpiration, Caching.CacheItemPriority.Normal, null); //无返回值,如果已经存在,则覆盖。 Cache.Insert("msg", "welcome");
因为Cache中存储的是没有序列化的对象,所以当保存的是一个引用类型的实例,比如一个数组,后续往数组中加入一个值后,则Cache中的值也会发生相应的变化。
读取
string str = Cache["msg"] as string;
修改
无法修改,只能被覆盖
删除
Cache.Remove("msg");
3. Session
继承自 HttpSessionState 类,当一用户首次向Web应用程序发起一次请求,Web 应用程序便为这个用户创建了一个session。默认情况下,只要用户持续不断地访问这个web应用程序,那么 session 就会一直存在。如果当用户关闭浏览器,则 session 就失效了,或者用户不再向 web 应用程序发起任何请求时,超过20分钟,那么session也就自动失效了。
添加
Session["msg"] = "123"; //如果已经存在则覆盖,否则创建,key 不区分大小写。 Session.Add("msg","123"); //和上句效果一样
因为Cache中存储的是没有序列化的对象,所以当保存的是一个引用类型的实例,比如一个数组,后续往数组中加入一个值后,则Cache中的值也会发生相应的变化。
读取
string str = Session["msg"] as string;
修改
Session["msg"] = "234";
删除
Session.Remove("msg"); Session.RemoveAll(); Session.Clear(); //与 RemoveAll 一样
使当前的Session失效
Session.Abandon();
InProc的模式下,Session_End 将被触发。那么下次对这个 web 应用程序的请求将会触发一个新的Session(SessionId可能使用旧的);单纯的关闭浏览器,Session_End 不会触发。只有当Session因为生命周期结束或者调用 Session.Abandon 时才会触发。
一般在 Session 超时或删除之后,SessionID保持不变,因为Session过期后,服务器端会清除数据,但是 SessionID 保存在客户端(Session Cookie 中),所以只要浏览器不关闭则 Http 头中的SessionID就保持不变。
Session_End 是由独立线程触发的,所以在 Session_End 中无法使用 HttpContext 对象,即无法使用 Response.Redirect 和 Server.Transfer 等方法。
Session 默认为 InProc, 保存在进程中,但这个进程不稳定,可能会导致存储在进程内的值意外丢失。
导致进程不稳定的几种原因:1. 配置文件中 ProcessModel 标签的 memoryLimit 属性。2. Global.asax 或者 Web.Config 文件被更改。 3. Bin 文件夹中的Web程序被修改。4. 杀毒软件扫描了一些.config文件。
4. Cookie
Cookie是 Web 应用程序在用户硬盘上存放的一段包含键值对的文本。
Response.Cookie["msg"].Value = "welcome"