5_状态管理
状态管理的必要性
浏览器向服务器请求某个页面,服务器处理完返回该页面对象,
之后在服务器端会清除该页面对象的数据,就是是对同一个页面的多次请求,服务器每次也都是返回一个新的对象实例,如果用户需要保存页面中的数据,就需要进行状态管理。
状态管理分类:
1、视图状态管理:视图状态
视图状态是在单个页面(在单个页面的多次回传请求过程)中保存信息的第一选择。视图状态依赖于字典集合。
视图状态中的内容在服务端会被序列化后保存在一个隐藏域中,作为页面中的一个隐藏控件跟随页面回发到客户端浏览器。
图示:
视图状态工作原理:
视图状态在服务器端处理时是一个字典集合,当页面处理完毕后,视图状态中所有的信息会进行序列化操作,形成Base64编码的单个字符串保存在页面中id为__VIEWSTATE的隐藏域控件中,当用户操作导致页面回传时,此隐藏域中的信息会随着表单一起回发到服务器端,系统会将其内容还原为保存前的信息。
使用格式:
保存数据
ViewState["Key"] = Value;
取数据
object obj = ViewState["Key"]
保存的位置:客户端的隐藏域控件
保存的数据类型:object
缺点
不跨页面,不跨用户
当存储大量和复杂数据时,会让客户端浏览器的解析速度受到影响,会占用大量带宽
当视图状态保存数据为对象类型时,要将对象标记为可序列化类,也就是在类前面加上Serializeable特性
2、应用程序状态管理
应用程序状态管理指:web应用程序在运行过程中需要对整个应用程序级别的信息进行保存或者读取的操作。简单来说就是在Web服务器运行期间保存或者读取数据的方式。
应用程序状态管理的几种方式
- 使用Application对象进行信息处理
- 使用Global类(全局类)的静态属性进行信息处理
- 使用应用程序缓存进行信息处理
——Application对象的使用
Application属性是Page类中定义的属性,返回值类型是HttpApplication类型的对象,这种类型的对象主要用来进行全局信息保存。
作用:用来进行全局信息共享,任何一个用户通过客户端登录到这个网站都能通过服务器看到这个对象里的数据
语法:通过键值对方式进行操作
保存数据:value为object类型,可以保存任意信息且无需序列化
this.Application[string name]=value;//
读取数据:对象中的信息需要先声明再提取,并且在提取时需要进行类型转换
object obj=Application[name];
特点:
1、跨用户:任意一个用户写入在Application里面的数据,其他用户也能读取。
2、跨页面:在任意页面写入的数据,其它任意页面也能读取。
保存位置:
服务器端的内存中,所以服务器端关闭项目后,Application里的数据就会清空
数据保存生命周期
数据写入 --> 应用程序关闭(或手动移除)
移除操作:
this.Application.Remove("key");
加锁和解锁:
Application因为是用户共享的,所以可能会出现多个用户同时操作这个Application对象,为了避免发生这种冲突导致并发性的异常,
当一个用户在操作这个对象的时候进行加锁,这样其它用户就操作不了这个对象了,只有等当前用户操作完了解锁 之后才能操作。
加锁: this.Application.Lock();
解锁:this.Application.UnLock();
如:
缺点:
因为保存的类型为object类型,所以写入进行装箱,读取需要拆箱,如果处理大量数据时,可能会影响效率
使用场合(全局信息共享信息的保存)
常用于:聊天室中的在线用户列表、网站中在线人员总数、系统公告等
——Global类(全局应用程序类)的使用
扩展名:asax,Global类继承于HttpApplication类,所以也可以把Global类看成是全局信息类
每个客户端在访问服务器的时候都会经过这个类里面的某些事件处理程序,因此可以像Application那样实现某些限制,此文件应该存放于应用程序根目录中
语法:
1)在项目中添加一个Global.asax全局应用程序类,建议先把原来全局应用程序类的删了重新添加,因为原来的里面只有一个事件处理程序,新建的默认有7个事件处理程序
2)在Global类中定义静态属性,如果要对属性初始化,建议在Application_Start()事件中执行初始化。
3)使用:Global.属性即可
保存位置和特点和Application一致。
作用:
其作用为编写应用程序级别的事件响应方法,也可以在Globla类里创建静态属性,每个用户登录的时候在里面的事件处理程序里即可共享数据,以便于全局使用:
创建时默认的7个事件处理程序:
1、 Application_Start():
程序启动时触发,整个项目运行的时候会执行一次,只会执行一次,可以做一些初始化的工作
2、 Session_Start():
会话启动时触发(Session创建的时候会执行,每台客户端的浏览器第一次访问服务器的时候就会自动为当前客户端创建Session,同一台客户端用不同的浏览器访问也会重新创建会话,但是,如果在浏览器访问过了该服务器的话,在同一个浏览器新建一个浏览器窗口则不会重新创建会话,也就是不会将其任务是一个新用户,原理就是根据浏览器首次访问服务器来创建会话的)
3、 Application_BeginRequest()
开始请求页面时触发(每请求一次就会触发一次,不管是哪台客户端)
4、 Application_AuthenticateRequest()
启用身份验证时触发(进行验证时触发)
5、 Application_Error()
可以实现一个全局异常处理(应用程序报异常的时候触发)
6、 Session_End()
会话结束时触发(Session销毁的时候执行)
7、 Application_End()
应用程序结束时触发
使用场合(全局信息共享信息的保存)
可以用来记录用户登录日志
如:
也可以用来记录聊天室中的在线用户列表
在Globla类里创建静态属性,每个用户登录的时候在里面的事件处理程序里创建静态资源,以便于全局使用:
3、会话级别状态管理
Web应用程序除了需要保存整个应用程序级别的信息以外,还需要保存特定用户的信息,并且此信息为保密信息,即不可被其它用户读取到。比如用户的密码、角色信息、个性化菜单、权限信息、私密信息等,
Asp.NET应用程序中有两种方式实现保存用户的个人信息
- 使用Session对象进行会话信息保存
- 使用Cookie对象进行个人信息保存
——Session对象(会话状态)
Session对象是System.Web.SessionState.HttpSessionState类型的实例,HttpSessionState这种类型就是用来保存用户客户端的特别信息。
Session就是会话级别状态管理的一种实现。所以可以认为Session就是会话
原理:
每一个Session(会话)服务器端都会单独的开辟内存空间,为了区分那个会话空间是属于哪个客户端服务器的,所以服务器端采用SessionID来进行区分,Session是为了每个用户(客户端)独立开辟的空间,其它客户端无法访问到,因为在服务端的内存不一样。
Session是如何区分用户和同一个用户里面的不同数据的?Session本身就是一个键值对容器,这个容器里又存了N个Session,在这一子Session里存数据(通过SessionID来区分数据,也就是自己取的key),父容器通过不同的键(SessionID)来区分用户
使用:
这种方法是你自己手动创建的Session(相当于子Session)来存数据,和服务器自动创建(相当于父Session)的区别就是,服务器创建的会话的键是服务器分给浏览器一个SessionID作为键,也就是说会话在用户第一次访问应用程序页面时服务器自动创建,为其分配空间,而自己创建的Session的键可以自己取名字,本质上也是存储在服务器为当前这个会话开辟的空间里面的
保存数据:Session[string name]=value;//value为object类型
读取数据:object obj=Session[name];
保存位置:
为每一个Session在服务器端单独开辟内存,保存它的数据
会话的生命周期
- 会话在用户(浏览器)第一次访问应用程序页面时自动创建,此后通过页面转向等方式在请求服务器时不再识别为一个新会话。也就是说会话不会在用户每次访问服务器时创建。
- 每个客户端浏览器进程在服务器端只会被识别为一个会话,除非打开一个不同的浏览器,这样服务器就会新建一个会话
- 不会因为客户端关闭Web页面而释放会话所占用的空间,因为会话Session存在服务器的,客户端把浏览器关了也不会影响服务器。
会话释放只有两种可能
——1)用户访问超时(设置Session过期时间):
即用户在指定时间内不与服务器端联系,即判定为会话超时,服务器端会自动释放该用户的会话
原理:可能有些用户第一次访问服务器后,就可能长时间不会再去和服务器取得任何联系,如果这时候服务器还继续为它保存特定的信息的话,那么就会无形当中增加服务器端内存的压力,所以会给会话设置一个超时时间,过了这个时间之后就释放掉这个会话在内存中占用的空间,等这个用户重新访问时,再为其重新开辟新的空间。
如何设置Session过期时间(默认为20分钟)两种方法:
①在全局应用程序类Global里面的会话启动时触发的事件处理程序Session_Start()里设置:
Session.Timeout = 20;//单位分钟
②在web.config配置文件里设置
<system.web>
<sessionState timeout="20" />
</system.web>
——2)用户主动通过会话对象的方法进行释放
this.Session.Abandon();
调用Abandon()不会立即释放会话,会在这次请求结束时才释放,会引发Session_End()事件,其实就是要等到Session_End()事件处理程序执行结束后才释放会话,所以在Session_End()事件里也能获取到Session里面的数据。
如:
会话有关的全局事件处理
会话创建时会引发Session_Start事件
会话销毁时会引发Session_End事件
Global文件中关于会话的事件应用
统计在线总人数
会话创建时总人数加一
会话销毁时总人数减一
会话销毁同时从在线用户名单中删除当前用户名
注意:在使用会话时需要考虑服务器内存的消耗,尽可以减少使用会话保存信息的操作
——Cookie对象
Cookie是System.Web.HttpCookie类型的实例
Cookie信息保存在浏览器端,即不占用服务器端内存
使用Cookie可以为每台电脑的指定用户创建长时间保存的个人信息
语法:
写入:由服务器端将数据写入客户端的cookie中:
Reponse.Cookies.Add(cookie对象);
读取:用Request从客户端发送的请求里面读取cookie里的数据
HttpCookie hc=Request.Cookies["name"];
如:创建cookie后,在浏览器里也可以看到
Cookie分类:
临时性Cookie:创建的时候没有设置过期时间。信息保存在浏览器端的浏览器进程中,一旦浏览器关闭,Cookie信息自动消失
持久性Cookie:创建的Cookie对象设置过期时间,过期时间是DateTime类型的值,数据保存在客户端浏览器端的硬盘文件中
保存的数据类型:
Cookie里面只能存字符串类型
特点:
1)跨页面:在任意页面写入的数据,其它的任意页面都能读取
2)不跨用户:每个用户只能访问自己保存的数据
Cookie的使用场合
记录匿名用户在网站中的个性化定制
记录匿名用户在购物网站中的购物车
记录注册用户在指定网站的用户名及密码信息以避免在有效时间内的再次登录操作
身份验证操作时用户有效性票据保存
总结集几种状态管理
ViewState | Application | Session | Cookie | |
---|---|---|---|---|
保存内容类型 | 可序列化类型 | 任意object | 任意object | string |
储存位置 | 页面隐藏域中 | 服务器端内存 | 服务器端内存 | 客户端内存或硬盘 |
生命周期 | 页面回传过程中 | 声明至应用程序关闭 | 声明至会话结束 | 声明至浏览器关闭或过期 |
跨页面性 | 不跨页面 | 跨页面 | 跨页面 | 跨页面 |
跨用户性 | 不跨用户 | 跨用户 | 不跨用户 | 不跨用户 |