您的位置:首页 > 编程语言 > ASP

ASP.NET 状态管理(cookie、Session)

2016-05-01 14:55 555 查看


cookie

自定义cookie提供了保存备用数据的另一个选择。cookie在用户的硬盘上创建一个小文件(临时cookie保存在Web浏览器的内存)。

cookie的优点

对用户透明,他们不必知道需要保存哪些信息。
很方便的由应用程序中的任意页面使用,甚至还可以保存很久以便在不同的访问中使用。

cookie的限制

和查询字符串一样,只能使用简单的字符串信息
如果用户找到并打开cookie文件,它们很容易被修改。因此不适合保存复杂,私有的信息或者大量的数据。
部分用户还会禁用cookie,不过大部分情况下用户会接受cookie,因为它们被太多的站点使用。

cookie的使用

Request对象和Response对象都提供了Cookies集合。
使用Request对象读取cookie
使用Reesponse对象设置cookie

HttpCookiecookie=newHttpCookie("Preferences");

cookie["Language"]="English";

cookie["Country"]="US";

Response.Cookies.Add(cookie);


用这种方式添加的cookie在每次请求时都会回发,它直到用户关闭浏览器时才会消失。但我们可以设置过期时间来设置长期存在的cookie(以临时Internet文件的形式存在用户硬盘上)。

//Thiscookielivesforoneyear.

cookie.Expires=DateTime.Now.AddYears(1);


使用Request.Cookies集合通过cookie的名字来读取cookie:

HttpCookiecookie=Request.Cookies["Preferences"];


//becausetheusercoulddisablecookie,somustcheckit

stringlanguage;

if(cookie!=null)

{

language=cookie["language"];

}


移除cookie的唯一方法是使用一个已过期的cookie来替换它:

HttpCookiecookie=newHttpCookie("LanguagePref");

cookie.Expires=DateTime.Now.AddYears(-3);

Response.Cookies.Add(cookie);



会话状态Session

会话状态时状态管理最重要的一部分!通过它你可以在一个页面存储数据而另一个页面获取数据,最重要的是它还支持包括自定义数据类型在内的任意对象类型。每个访问应用程序的客户端都有不同的会话且包含不同的信息,因此Session是跨页浏览时保存用户购物车内容的理想场所

Session不是免费的,它迫使Web服务器在服务器内存中保存额外的信息,即使信息量很小,成百上千个用户访问网站时也很可能会迅速造成一场灾难。


会话架构

ASP.NET使用一个唯一的120位标识符跟踪会话,并使用一个私有的算法来生成这个值,从统计学上说可以保证这个值是唯一的且足够随机,从而恶意用户不能反向设计或猜出指定用户将要使用的值。

这个值是客户端和服务器端传递的唯一值。客户端发送会话ID后,ASP.NET查找相应的会话,从状态服务器获得序列化的数据并将其转换为活动的对象,最后将这些对象放到可以用代码访问的集合,这个过程是自动完成的。

我们知道,ASP.NET处理HTTP请求时会经过一个包含不同模块的管道链,这些模块可以响应应用程序事件。链上的一个模块是SessionStateModule(在System.Web.SessionState命名空间中)

SessionStateModule模块负责产生会话ID,从外部提供程序中获取会话数据,并把数据绑定到请求的上下文中。页面处理完毕后,该模块还会保存会话信息。但很重要的一点要明白,SessionStateModule并不保存会话数据,而是会话状态持久化在外部组件中,这些外部组件称为状态提供程序

会话状态时ASP.NET可插拔架构的另一个例子。状态提供程序是可以实现IHttpSessionState接口的任意类,也就是说构建(或购买)一个新的
.NET组件,你就可以自定义如何处理会话状态。

ASP.NET有3个预建的状态提供程序,它们允许你在进程独立服务(windows服务)SQL
Server数据库
中保存信息。


使用会话状态

可以通过System.Web.SessionState.HttpSessionState类和会话状态交互,它建立在Session对象中,由ASP.NET网页提供。

会话状态在下面这些情形下会丢失:

用户关闭并重启浏览器
用户通过另一个浏览器访问同一页面(不同浏览器处理这一方式是不同的)
没有活动导致会话超时,默认情况下,闲置20分钟后会话会超时
程序员调用Session.Abandon()方法结束会话

在前2种情况下,会话其实还保存在服务器的内存中,Web服务器并不知道用户已经关闭了浏览器或者更换了窗口,会话在内存中游荡,但由于不能访问到,直至最终过期。此外应用程序域重建时会话也会丢失,这个过程透明的发生。

HttpSessionState成员
Count当前会话集合中的项目数
IsCookieless指示当前会话是存储在cookie中还是嵌入在修改的URL中
IsNewSession指示会话是否是只为当前请求而创建的
Mode一个枚举值,用于指示ASP.NET如何保存会话状态信息
SessionID当前客户端的会话标识字符串
StaticObjects通常不使用(为了向后兼容ASP程序的)
Timeout超时的时长,该值可以通过代码修改
Abandon()立即取消当前会话并释放它占用的全部内存空间,退出页面时很有用,确保服务器内存得到快速重用
Clear()不改变当前会话标识符的情况下清空所有的会话项目


配置会话状态

可以通过web.config文件中的<sessionState>元素为应用程序配置会话状态,下面是所有可用设置的一个快速浏览:

<system.web>

<!--Othersettingsomitted-->


<sessionState

mode="Off|InProc|StateServer|SQLServer|Custom"

stateConnectionString="tcpip=127.0.0.1:42424"

stateNetworkTimeout="10"

sqlConnectionString="datasource=127.0.0.1;IntegratedSecurity=SSPI"

sqlCommandTimeout="30"allowCustomSqlDatabase="false"

useHostingIdentity="trye|false"

compressionEnabled="true|false"

cookieless="UseCookies"cookieName="ASP.NET_SessionId"

regenerateExpiredSessionId="true|false"

timeout="20"

customProvider=""

/>

</system.web>


1.Mode

模式设置允许你配置在请求间保存会话状态信息的会话状态提供程序

Off

禁用应用程序中所有页面的会话状态管理

InProc

类似于传统ASP中保存会话的方式,它指示ASP.NET在当前应用程序域中保存信息。这种方式有最好的性能却具有最差的持久性,如果重启服务器,状态信息将丢失。InProc是默认选项,它对于多数小型网站有意义,不过在Web集群中根本不能工作。你需要使用SQLServer状态服务才能使会话状态在服务器间共享。另一个不使用它的原因是它会产生较多的会话碎片。ASP.NET应用程序会因为多种活动而回收,包括更改配置,更新页面,如果你发现你的应用程序域不断重启而导致会话过早丢失,你可以选择另一种更强健的会话状态提供程序

使用进程外或SQLServer状态服务时,请记住你需要考虑更多的问题:

使用StateServer或SQLServer模式时,要保存在会话状态中的对象必须是可序列化的,否则ASP.NET不能够将对象传送到状态服务器或保存到数据库中
如果在集群中,则需要一些额外的配置以保证所有Web服务器同步,否则服务器会采用不同的方式编码会话状态信息,当用户由一台服务器路由到另一台服务器时会产生一个问题,解决该问题的办法是修改machine.config文件的<machineKey>节以确保所有服务器使用相同的设置。
如果不使用进程内的状态提供程序,SessionStateModule.End事件就不会触发,所有global.asax或者HTTP模块中所有注册该事件的处理程序将被忽略

StateServer

采用该选项时ASP.NET使用一个独立的Windows服务来管理状态。即使该服务于Web服务器在同一台服务器上。它也会在ASP.NET主进程外加载,这样当ASP.NET进程需要重启时,可以为状态提供基本的保护。代价是两个进程间传递信息时将导致延迟,如果频繁访问和更改状态信息,则速度会明显变慢,让人无法忍受

使用StateServer选项时,要为StateConnectionString设置一个值。该值定义了运行服务的计算机的TCP/IP地址和端口号。当然,在应用程序能够使用服务之前必须将其启动。

使用StateServer选项时还可以设置一个可选的stateNetworkTimeout特性,该特性指定放弃请求前等待服务器响应的最大秒数,默认值是10秒。





SQLServer

该选项指示ASP.NET使用sqlConnectionString特性设定的SQLServer数据库保存会话信息。这是目前最具弹性同时也是目前最慢的状态存储方式,使用该模式需要一台装有SQLServer的服务器。设置sqlConnectionString时通常需要指定数据源(服务器地址),除非使用SQL整合安全方式,否则还要指定用户名和密码。此外,还需要安装临时会话数据库和一些特定的存储过程。其中存储过程负责保存和获取会话信息。

ASP.NET使用命令行工具aspnet_regsql.exe实现这一目的。使用aspnet_regsqt.exe创建会话存储数据库时,要提供-ssadd参数,此外,使用-S参数表明数据库服务器的名称,-E参数使用当前登录的Windows用户账户登录数据库。使用-ssremove参数可以移除ASPState数据库

这个命令在当前计算机上创建会话存储数据库,使用默认的数据库名称ASPState:
aspnet_regsql.exe-Slocalhost-E-ssadd
这个命令使用了假名localhost,它告诉aspnet_regsql.exe连接当前计算机上的数据库服务器,可以用数据库服务器所在的计算机名替代它。

标准会话状态超时时间也对SQLServer状态管理有效。因为aspnet_regsql.exe工具同时还创建了一个名为ASPState_Job_DeleteExpiredSessions的新SQLServer执行计划。只要SQLServerAgent服务在运行,这个执行计划每分钟执行一次。

此外,每次重启SQLServer时状态表会被删除,无论会话是否超时。这是因为此表是创建在tempdb数据库里,它是一个临时的存储区域。如果这不是你所期望的行为,你可以告诉aspnet_regsql.exe在ASPState数据库里安装持久状态表。这是可以使用参数-sstypep(Persisted)

aspnet_regsql.exe-Slocalhost-E-ssadd-sstypep
现在,会话记录将保存在数据库里,即便重启了SQLServer也是如此。

最后一个选项是是创建一个非默认的状态表,这时使用参数-sstypec(Custom),并通过-d参数提供数据库名称。

aspnet_regsql.exe-Slocalhost-E-ssadd-sstypec-dMyCustomStateDb
采用这种方法创建的是持久会话表。

如果使用了自定义数据库,还需要对web.config做两处微调:

<sessionStatemode="SQLServer"allowCustomSqlDatabase="true"sqlConnectionString=

"datasource=localhost;IntegratedSecurity=SSPI;InitialCatalog=MyCustomStateDb"/>


Custom

使用自定义模式时,需通过customProvider特性指定会话状态存储提供程序。这个特性指向App_Code文件夹中一个类的名字,或者在Bin目录或GAC中某个已编译的程序集的名字。创建自定义状态提供程序是一项需要小心处理的底层任务,需要保证安全性,稳定性和可扩展性,因此最好由可靠的第三方设计和测试

2.压缩

他可以减小序列化会话数据的大小。把enableCompression设置为true后,会话数据在传送到进程外会话状态存储时才起作用,因为这种情况下数据才会被序列化。

会话数据是使用System.IO.Compression.GZipStream类自动进行压缩的。

会话状态压缩最有意义的两个场景如下:

在内存里存储了大量会话状态数据时:Web服务器内存是非常珍贵的资源。理想情况下,会话状态用于少量的信息段,后端数据库处理大量数据的长期储存。但如果情况不是这样并且进程外状态服务器拥有大量的内存,压缩式潜在的解决方案。
在其他计算机存储会话状态数据时:在某些大型的Web应用程序中会话状态是在进程外的(一般是SQLServer)并且在单独的计算机上。因此,ASP.NET需要在网络连接上传送会话信息。显然,这样的设计降低了执行速度,不过,对于某些需要大量存储会话状态信息且流量非常大的网站而言,这仍然是最佳的折中方案。

第一种情况,压缩牺牲了CPU的时间换取了Web服务器内存。

第二种情况,压缩牺牲了CPU的时间节省了网络流量。

注:

实际的压缩量由于数据类型的不同差异很大,但在微软的测试中,客户端得到30%到60%的数据减少,在这些场景中它确保了性能的极大提升。

3.cookieless

HttpCookieMode枚举值:
UseCookies无论浏览器或设备是否禁用cookie,总是可以使用cookie(默认选项)。

如果设备不支持cookie,后续的请求会话信息会丢失,因为每次请求都会获得新的标识符
UseUri无论浏览器或设备是否支持cookie,都不会使用cookie。会话ID被存储在URL中。
UseDeviceProfileASP.NET通过检查BrowserCapabilities对象来决定是否使用无cookie会话。

(只指明了设备应当支持的---而没有考虑用户可能禁用了浏览器中的cookie)
AutoDetectASP.NET通过尝试设置和读取cookie(一种常用的Web技术)来确定浏览器是否支持cookie

该技术可以正确判断浏览器是否支持cookie但却禁用了cookie,在这种情况下,将使用无cookie会话。
使用无cookie模式时,例如下面这样:

<sessionStatecookieless="UseUri"。。。>

会话ID会自动插入到URL中,ASP.NET获得请求时,它将移除ID,检索会话集合,将请求送到相应的目录:

http://localhost/WebApplication/(amfdddgd677sdgfdfg)/Page.aspx

因为会话ID是插入到URL中的,所以相对链接也会自动获得会话ID,真正限制无cookie会话状态的是:不能使用绝对链接,因为他们不包含会话ID

ASP.NET默认允许重用会话标识。如果使用了一个含有过期会话的查询字符串,ASP.NET会用这个ID重新创建一个会话。问题是某个会话ID会不经意的出现在某些公共场合,例如作为搜索引擎的查询结果。这样多个用户会使用同样的会话ID来访问服务器并加入到含有相同共享数据的相同会话中。为避免这一潜在的安全问题,使用无cookie会话时,推荐加入可选的
regenerateExpiredSessionId特性,并把该值设为true。这样当用户使用已经过期的会话ID时,会创建一个新的会话ID。这么做的唯一缺点是,当前页面所有视图状态和表单数据将全部丢失,因为ASP.NET执行了一次重定向来保证浏览器使用新的会话ID


可以通过Session对象的IsCookieless属性来检查当前是否在使用无cookie的会话。

4.timeout

这个设置体现了会话状态最重要的折中。不同的分钟数会给服务器负载及应用程序性能带来非常大的影响。理想状态下,最佳的时间应当足够短,保证服务器内存能及时释放,同时这个时间也应该足够长,保证客户端在暂停一段时间后会话不会丢失还能继续使用。

可以在代码中设置:

Session.Timeout=10;


会话状态安全

会话状态中的信息非常安全,因为它们只保存在服务器上。然而含有会话ID的cookie可能很容易被篡改。就是说一个恶意用户可以偷走cookie然后在另一台计算机上继续使用。

一个常用的方法是使用自定义的会话模块来检查客户端IP地址的变化。唯一真正有效的方法是仅在使用了SSL的网站上使用会话cookie。采用这种方法,会话cookie被加密从而在其他计算机上不可用。如果使用这种方式,将会话cookie标识为安全cookie才有意义,这样cookie只能通过SSL连接传送。这使得用户不能将URL由https://修改为可以不使用
SSL发送cookie的http://。

Request.Cookies["ASP.NET_SessionId"].Secure=true;//这样的cookie必须在使用了SSL的网站上传送
这条代码应在用户通过验证后立即使用,另外还要确保会话状态中至少有一点信息,这样它才不被取消。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: