Session,ViewState,Application用法
ViewState
基本理论:
session值是保存在服务器内存上,那么,可以肯定,大量的使用session将导致服务器负担加重. 而viewstate由于只是将数据存入到页面隐藏控件里,不再占用服务器资源,因此, 我们可以将一些需要服务器"记住"的变量和对象保存到viewstate里面. 而sesson则只应该应用在需要跨页面且与每个访问用户相关的变量和对象存储上. 另外,session在默认情况下20分钟就过期,而viewstate则永远不会过期.
数据类型:
但viewstate并不是能存储所有的.net类型数据,它仅仅支持String、Integer、Boolean、Array、ArrayList、Hashtable 以及自定义的一些类型.
其他考虑
当然,任何事物都有两面性, 使用viewstate会增加页面html的输出量,占用更都的带宽,这一点是需要我们慎重考虑的. 另外, 由于所有的viewstate都是存储在一个隐藏域里面,用户可以很容易的通过查看源码来看到这个经过base64编码的值.然后再经过转换就可以获取你存储其中的对象和变量值.
其实,对于viewstate的安全性问题,asp.net还给我们提供了更多的选择.一般如果要保护viewstate有两种方式: 一种是防篡改,一种是加密. 一说到防篡改,我们就想起了使用散列代码. 没错, 我们可以在页面顶部加入如下代码:Page EnableViewStateMAC=true。这样asp.net就会自动的在viewstate中追加一个散列码,在页面回传时,服务器根据回传的viewstate生成一个散列码,再与回传的散列码相比较,如果不对,则丢弃该viewstate,同时控件将恢复初试状态. (默认情况下asp.net是通过SHA1算法而不是md5算法来生成散列,不过这个可以在machine.config里面配置machineKey validation="MD5"即可),而viewstate加密就更简单了, 只要在machine.config里设置一下machineKey validation="3DES"即可实现用des加密viewstate了.
使用方法
怎么在客户端,存取ViewState?
应用环境
一些与安全性无关,数据量较小,需要长时间操作的参数,应该用ViewState存取。
在webgis中,地图的各种相关状态,如zoom, center, layers, visibility等,用viewstate存取的话,就不存在session过期的问题,网页可以永远使用,甚至可以下载保存,在进行地图请求,或iframe到第三方的应用中。
昨天看到一个文章,作者在自己的页面中定义了几个全局变量,类型是static,但是这样的定义会存在问题,当一个用户访问的时候不会有问题,但是当大量用户并发访问系统的时候,页面中的这些static类型的全局变量就会出现问题了,然后作者改用了Session变量保存以前由static类型全局变量纪录的数据,因为Session是状态量,只是和某个访问进程相关,这样就不会出现由于static类型引起的问题了。
但是这样的话系统中的Session就太多了,我总认为这样不太好,虽然每个一个Session都有一个ID不会冲突。ASP.NET引入了ViewState,可以记录同一个页面的不同PostBack中的一些数据值。
asp.net ViewState用法:
ASP.NET中的ViewState是ASP.NET中用来保存WEB控件回传时状态值一种机制.在WEB窗体(FORM)的设置为runat="server",这个窗体(FORM)会被附加一个隐藏的属性_VIEWSTATE._VIEWSTATE中存放了所有控件在ViewState中的状态值.
ViewState是类Control中的一个域,其他所有控件通过继承Control来获得了ViewState功能.它的类型是system.Web.UI.StateBag,一个名称/值的对象集合.
当请求某个页面时,ASP.NET把所有控件的状态序列化成一个字符串,然后做为窗体的隐藏属性送到客户端.当客户端把页面回传时,ASP.NET分析回传的窗体属性,并赋给控件对应的值.当然这些全部是由ASP.NET负责的.
定义ViewState属性
Public int PageCount
{
get{return(int)ViewState["PageCount"];}
set{ViewState["PageCount"]=value;}
}
使用ViewState的条件
如果要使用ViewState,则在ASPX页面中必须有一个服务器端窗体标记(<formrunat=server>).窗体字段是必需的,这样包含ViewState信息的隐藏字段才能回传给服务器.而且,该窗体还必须是服务器端的窗体,这样在服务器上执行该页面时,ASP.NET页面框架才能添加隐藏的字段.
(注意:可以片面认为:ViewState是为非表单控件提交数据而准备;其实呢,是由于互联网遵循TCP/IP协议的无记忆性, 网页需要知道你在上一页都干了什么,viewstate就是传递“你干的事情”或者什么都没干也会有一些初始化的必要数据)
Page的EnableViewState属性值为true.
控件的EnableViewState属性值为true.
提醒:
1.当存在页面回传时,不需要维持控件的值就要把ViewState禁止.
2.ViewState的索引是大小写敏感的.
3.ViewState不是跨页面的.
4.为了能包存在ViewState中,对象必须是可流化或者定义了TypeConverter.
5.控件TextBox的TextMode属性设置为Password时,它的状态将不会被保存在ViewState中,这应该是出于安全性的考虑.
6.在页面没有回传或重定向或在回传中转到(transfer)其他页面时不要使用ViewState.
7.在动态建立控件时要小心它的ViewState.
8.当禁止一个程序的ViewState时,这个程序的所有页面的ViewState也被禁止了.
9.只有当页面回传自身时ViewState才是持续的.
设置ViewState
ViewState可以在控件,页,程序,全局配置中设置.缺省情况下EnableViewState为true.如果要禁止所有页面ViewState功能,可以在程序配置中把EnableViewState设为false.
----------------------------------------分割线---------------------------------------
Session
在Web开发的早期,Web页面彼此是相互独立的。它们很少需要了解其他页面的内容(如果需要了解,一般通过查询字符串或通过Form的方式传递)。随着Internet的发展,Web页面也变得更加复杂,仅仅浏览一个页面查看它的内容是远远不够的。现在的Web站点的设计都希望考虑工作流的问题——即需要从一个页面移动到另一页面。
因此会话状态(Session State)就应运而生。会话状态变量允许Web页面保存和用户浏览器的具体一次“会话”的相关的信息。在同一次会话中接下来的页面可以按需要引用这些会话变量。该信息被绑定到用户浏览器会话。一旦浏览器会话关闭,该信息就被删除。该信息存储在Web服务器上,在客户端浏览器的所有调用中都是一种保存的。
(例如:用session[“password”]=password (这是字段名) 来保存用户密码, 当重定向或者转移到本网站的另外页面时,在当前页就得判断session里面是否有值, 若为null , 则转到login页面) 由于cookie是本地存储, 浏览器可以禁用cookie,因此session可以在网站的一些关联页面之间传送一些必要的数据或者参数(但是session会有服务器压力)
当回送发生时,ASP.NET能够使用它在用户第一次连接时创建的唯一的SessionID(SessionID是在服务器上对客户端浏览器唯一的标识,每个客户端浏览器有一个对应的SessionID)来检索会话信息(如果浏览器支持Cookie,并且ASP.NET Web页面配置为使用Cookie);或者通过被ASP.NET追加到URL中的一个加密的字符串来检索会话信息(对于浏览器不支持Cookie或者ASP.NET Web 页面配置为不使用Cookie的情况)。
Session在web.config的配置:
<sessionState mode="[Off|InProc|StateServer|SQLServer|Custom]" timeout="number of minutes" cookieName="session identifier cookie name" cookieless= "[true|false|AutoDetect|UseCookies|UseUri|UseDeviceProfile]" regenerateExpiredSessionId="[True|False]" sqlConnectionString="sql connection string" sqlCommandTimeout="number of seconds" allowCustomSqlDatabase="[True|False]" useHostingIdentity="[True|False]" stateConnectionString="tcpip=server:port" stateNetworkTimeout="number of seconds" customProvider="custom provider name"> <providers>...</providers> </sessionState>
Session的存储模式:InProc,StateServer,SQL Server,Custom,Off.默认存储和模式为InProc。
InProc 模式,此模式将会话状态存储在 Web 服务器上的内存中,将会话状态值和变量存储在本地 Web 服务器上的内存中。
StateServer模式,将会话状态存储在一个名为 ASP.NET状态服务的单独进程中。这确保了在重新启动 Web 应用程序时会保留会话状态,并让会话状态可用于网络场中的多个 Web 服务器。使用该模式需设定ASP.NET状态服务为启动。ASP.NET状态服务进程是独立于 ASP.NET 辅助进程或 IIS 应用程序池的单独进程。使用此模式可以确保在重新启动 Web 应用程序时保留会话状态,并使会话状态可用于网络场中的多个 Web 服务器。若设置StateServer模式,需设置stateConnectionString属性。如:
<configuration> <system.web> <sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424" cookieless="false" timeout="20"/> </system.web> </configuration>
SQLServer模式将会话状态存储到一个 SQL Server 数据库中。这确保了在重新启动 Web 应用程序时会保留会话状态,并让会话状态可用于网络场中的多个 Web 服务器。若要使用 SQLServer 模式,必须首先确保在 SQL Server 上安装了 ASP.NET 会话状态数据库。
<configuration> <system.web> <sessionState mode="SQLServer" sqlConnectionString="Integrated Security=SSPI;data source=ASPNETServer;" /> </system.web> </configuration>
Custom 模式,此模式允许您指定自定义存储提供程序。
Off 模式,此模式禁用会话状态。
在ASP.NET中,Session是一个带有方法和属性的.NET对象,可以在一个.NET会话状态对象中存储任何数据类型(包括用户定于的类和结构)。但是,存储数据也是以性能为代价,代价的大小取决于保存会话信息的多少,还是数据的类型信息。
简单示例
创建两个页面:一个页面(SessionAdd.aspx)来添加Session的Key和Value,另一个(SessionResult.aspx)来显示Session的信息。
SessionAdd的代码:
<div> Session Variable:<asp:TextBox ID="txtSessionVariable" runat="server" /><br/> Value: <asp:TextBox ID="txtSessionValue" runat="server" /><br /> <asp:Button ID="btnAdd" runat="server" Text="Add Session" onclick="btnAdd_Click" /> <asp:Button ID="banView" runat="server" Text="View Session" onclick="banView_Click" /> </div>
后台代码:
protected void btnAdd_Click(object sender, EventArgs e) { Session[txtSessionVariable.Text] = txtSessionValue.Text; } protected void banView_Click(object sender, EventArgs e) { Server.Transfer("SessionResult.aspx"); }
页面效果:
SessionResult.aspz页面:
<div> <asp:TextBox ID="txtSessionResult" runat="server" TextMode="MultiLine" Width="240px" Height="200px" /><br /> <asp:Button ID="btnBack" runat="server" Text="Clear and Back" onclick="btnBack_Click" /> </div>
后台代码:
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { StringBuilder sb = new StringBuilder(); foreach (String strKey in Session.Keys) { sb.Append(strKey); sb.Append("="); sb.Append(Session[strKey]); sb.Append("\n"); } txtSessionResult.Text = sb.ToString(); } } protected void btnBack_Click(object sender, EventArgs e) { Session.Clear(); Server.Transfer("SessionAdd.aspx"); }
页面效果:
以上的列子简单说明Session的添加,查看,清空。
基于性能的考虑,Session不应该存储任何依赖于外部链接性或关键资源的内容。
----------------------------------------------分割线-------------------------------------------------
设置Application的值的最好地方是在Global.asax文件中的Application_Start事件处理程序中。该事件每当应用程序第一次启动时触发,该事件在Web应用程序的生命周期中只触发一次,在随后的Web用户请求中不再被触发,知道应用程序或IIS被停止。
Application在使用时候直接使用Application的key或index就可以。如Application["UserCount"]=0;
在修改值为了保证数据的完整性必须锁定和解锁Application对象,因为应用程序的多个实例可能会在同一时间更新值,锁定和解锁使用Application对象的Lock()和Unlock()方法来完成。
Application.Lock(); int userCount =(int)Application["UserCount"]; userCount += 1; Application["UserCount"] = userCount; Application.UnLock();但是,使用这两个方法也是性能的损失,因为任何其他ASP.NET应用程序实例在等待Application对象解锁以访问它时,基本上时被阻塞的,因此,如果在以读/写方式使用Application对象,确保在锁定一个键值时执行最少量的代码。在锁定中分离出其他线程或运行时间很长的查询都是不明智的做法。