首页 > 代码库 > ASP.NET 状态服务 及 session丢失问题解决方案总结

ASP.NET 状态服务 及 session丢失问题解决方案总结

ASP.NET2.0系统时,在程序中做删除或创建文件操作时,出现session丢失问题。
采用了如下方法:
1、asp.net Session的实现:
asp.net的Session是基于HttpModule技术做的,HttpModule可以在请求被处理之前,对请求进行状态控制,由于Session本身就是用来做状态维护的,因此用HttpModule做Session是再合适不过了。
ASP.NET中Session的状态保持方式  
ASP.NET提供了Session对象,从而允许程序员识别、存储和处理同一个浏览器对象对服务器上某个特定网络应用程序的若干次请求的上下文信息。Session对应浏览器与服务器的同一次对话,在浏览器第一请求网络应用程序的某个页面时,服务器会触发Session_onStart事件;在对话超时或者被关闭的时候会触发Session_onEnd 事件。程序员可以在代码中响应这两个事件来处理与同一次对话相关的任务,如开辟和释放该次对话要使用的资源等。
   在ASP.NET的程序中要使用Session对象时,必须确保页面的@page指令中EnableSessionState属性是True或者Readonly,并且在web.config文件中正确的设置了SessionState属性。
  ASP.NET中Session的状态保持是由web.config文件中的<system.web>标记下的<sessionstate>标记的mode属性来决定的。该属性有四种可能的值:Off、Inproc、StateServer和SQlServer.
 设为Off会禁用Session.
  Inproc是缺省的设置,这种模式和以前的ASP的会话状态的方法是类似的,会话的状态会被保存在ASP.NET进程中,它的优点是显而易见的:性能。进程内的数据访问自然会比夸进程的访问快。然而,这种方法Session的状态依赖于ASP.NET进程,当IIS进程崩溃或者正常重起启时,保存在进程中的状态将丢失。
 为了克服Inproc模式的缺点,ASP.NET提供了两种进程外保持会话状态的方法。
  ASP.NET首先提供了提供了一个Windows服务:ASPState,这个服务启动后,ASP.NET应用程序可以将mode属性设置为“SateServer”,来使用这个Windows服务提供的状态管理方法。
 除了在web.config文件中设置mode属性为StateServer外,还必须设置运行StateServer服务器的IP地址和端口号.如果在IIS所在的机器运行StateServer则IP地址就是127.0.0.1,端口号通常是42424.配置如下:
 mode=”StateServer”
 stateConnectionString="tcpip=127.0.0.1:42424"
    使用这种模式,会话状态的存储将不依赖IIS进程的失败或者重启,会话的状态将存储在StateServer进程的内存空间中。
   另一种会话状态模式是SQLServer模式。这种模式是将会话的状态保存在SQL Server数据库中的。使用这种模式前,必须至少有一台SQL Server服务器,并在服务器中建立需要的表和存储过程。.NET SDK提供了两个脚本来简化这个工作:InstallSqlState.sql和UnInstallSqlState.sql。这两国文件存放在下面路径中:
  <%SYSTEMDRIVER%>\Winnt\Microsoft.NET\Framework\<%version%>\
要配置SQL Server 服务器,可以在命令行中运行SQL Server提供的命令行工具osql.exe
  osql -s [server name] -u [user] -p [password] <InstallSqlState.sql
例如:
  osql -s (local) -u as -p “”-i  InstallSqlState.sql
做好必要的数据库准备工作后,将web.config文件中的sessionstate元素的mode属性改为”sqlserver”,并指定SQL连接字符串。具体如下:
  mode="SQLServer"
    sqlConnectionString="data source=127.0.0.1;userid=sa;password=;Trusted_Connection=yes"
使用SQLServer模式处了可以使Session的状态不依赖于IIS服务器之外,还可以利用SQL Server的集群,使状态存储不依赖于单个的SQL Server,这样就可以为应用程序提供极大的可靠性。 

 
2、丢失原因:
转(1):Asp.net 默认配置下,Session莫名丢失的原因及解决办法 
      正常操作情况下Session会无故丢失。因为程序是在不停的被操作,排除Session超时的可能。另外,Session超时时间被设定成60分钟,不会这么快就超时的。
原因和解决办法写出来。
原因:
由于Asp.net程序是默认配置,所以Web.Config文件中关于Session的设定如下:
<sessionState 
mode=‘InProc‘
stateConnectionString=‘tcpip=127.0.0.1:42424‘
sqlConnectionString=‘data source=127.0.0.1;Trusted_Connection=yes‘
cookieless=‘true‘
timeout=‘60‘/>

我们会发现sessionState标签中有个属性mode,它可以有3种取值:InProc、StateServer?SQLServer(大小写敏感)。默认情况下是InProc,也就是将Session保存在进程内(IIS5是aspnet_wp.exe,而IIS6是W3wp.exe),这个进程不稳定,在某些事件发生时,进程会重起,所以造成了存储在该进程内的Session丢失。
[asp的Session是具有进程依赖性的。ASP Session状态存于IIS的进程中,也就是inetinfo.exe这个程序。所以当inetinfo.exe进程崩溃时,这些信息也就丢失。]

哪些情况下该进程会重起呢?微软的一篇文章告诉了我们:
1、配置文件中processModel标签的memoryLimit属性
2、Global.asax或者Web.config文件被更改
3、Bin文件夹中的Web程序(DLL)被修改
4、杀毒软件扫描了一些.config文件。
更多的信息请参考PRB: Session variables are lost intermittently in ASP.NET applications
解决办法:
      前面说到的sessionState标签中mode属性可以有三个取值,除了InProc之外,还可以为StateServer、SQLServer。这两种存Session的方法都是进程外的,所以当aspnet_wp.exe重起的时候,不会影响到Session。

      现在请将mode设定为StateServer。StateServer是本机的一个服务,可以在系统服务里看到服务名为ASP.NET State Service的服务,默认情况是不启动的。当我们设定mode为StateServer之后,请手工将该服务启动。这样,我们就能利用本机的StateService来存储Session了,除非电脑重启或者StateService崩掉,否则Session是不会丢的(因Session超时被丢弃是正常的)。
      除此之外,我们还可以将Session通过其他电脑的StateService来保存[如使用状态服务器]。具体的修改是这样的。同样还在sessionState标签中,有个stateConnectionString=‘tcpip=127.0.0.1:42424‘属性,其中有个ip地址,默认为本机(127.0.0.1),你可以将其改成你所知的运行了StateService服务的电脑IP,这样就可以实现位于不同电脑上的Asp.net程序互通Session了。

      如果你有更高的要求,需要在服务期重启时Session也不丢失,可以考虑将mode设定成SQLServer,同样需要修改sqlConnectionString属性。关于使用SQLServer保存Session的操作,请访问这里。
      在使用StateServer或者SQLServer存储Session时,所有需要保存到Session的对象除了基本数据类型(默认的数据类型,如int、string等)外,都必须序列化。只需将[Serializable]标签放到要序列化的类前就可以了。
如:
[Serializable]
public class MyClass
{
    ......
}
具体的序列化相关的知识请参这里。
至此,问题解决。

参考文章:
ASP.NET Session State FAQ
ASP.NET Session State
[ASP.NET] Session 详解
PRB: Session Data Is Lost When You Use ASP.NET InProc Session State Mode
PRB: Session Data Is Lost When You Use ASP.NET InProc Session State Mode
ASP.NET HTTP 运行时
.NET 中的对象序列化  
备注
(1)使用 StateServer 模式
确保运行 ASP.NET 状态服务的服务器是要存储会话状态信息的远程服务器。该服务与 ASP.NET 一起安装,其默认位置为
<驱动器>:\systemroot\Microsoft.NET\Framework\version\aspnet_state.exe。 
在应用程序的 Web.config 文件中,
设置 mode=StateServer 并设置 stateConnectionString 属性。
例如,stateConnectionString="tcpip=sarath:42424"。 
(2)使用 SQLServer 模式
在运行 SQL Server 的计算机(它将存储会话状态)上运行 InstallSqlState.sql
(默认的安装位置为 <驱动器>:\systemroot\Microsoft.NET\Framework\version)。
这将创建一个名为 ASPState 的数据库,该数据库具有新的存储过程并且在 TempDB 数据库中具有 ASPStateTempApplications 表和 ASPStateTempSessions 表。
在应用程序的 Web.config 文件中,设置 mode=SQLServer 并设置 sqlConnectionString 属性。例如,sqlConnectionString="data source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"。 
(3)示例 
以下示例指定若干会话状态配置设置。 

<configuration> 
<system.web> 
<sessionState mode="InProc" 
cookieless="true" 
timeout="20"/> 
</sessionState> 
</system.web> 
</configuration> 
要求 
包含于:<system.web> 
Web 平台:IIS 5.0、IIS 5.1、IIS 6.0 
配置文件:Machine.config、Web.config 
配置节处理程序:System.Web.SessionState.SessionStateSectionHandler 
请参见

ASP.NET 配置 | ASP.NET 设置架构 | SessionStateModule
[出现原因:]在Windows2003的服务器中的IIS6加入了应用程序池来回收一些无用的进程的功能,当由于网站程序的错误或访问量太多的导致的应用程序池会自动回收该进程,防止网站进入“死机”状态,而这时候的应用程序池的回收就会导致session变量被清除,就出现了session变量不见的现象。
为了解决这种在Windows2003下才出现的问题,我们在服务端起动ASP.NET State Service服务,并且在系统的machine.config做了一些改动。现在默认的情况下会话状态mode是StateServer。如果您的网站根目录下也配有一个web.config配置文件,请把mode="InProc"改成mode="StateServer",如下代码,就可以防止session变量的丢失:
<sessionState 
mode="StateServer" 
stateConnectionString="tcpip=127.0.0.1:42424" 
sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI" 
cookieless="false" 
timeout="30" 
/> 
+ 注:只适用于支持asp.net的用户。 

 
转(2):原因及一些解决之道 
将Session保存在State Server里:
1.启动服务“ASP.NET State Service”,
2.然后,修改web.config:
<sessionState
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
cookieless="false"
timeout="140000"
/>
注意://mode="StateServer"这种模式下即使修改页面也不会丢失session!
当然:mode="InProc"如果你的模式为这种,修改页面的时候会丢失session!!!!!!

在WebConfig里将Session的Mode设成SQLServer或者StateServer都不会丢Session的,
前者需要写入数据库,后者需要系统开StateServer服务。
  
原因1:
bin目录中的文件被改写,asp.net有一种机制,为了保证dll重新编译之后,系统正常运行,它会重新启动一次网站进程,这时就会导致Session丢失,所以如果有access数据库位于bin目录,或者有其他文件被系统改写,就会导致Session丢失。[目录的删除操作一定丢失session。asp.net的内部机制对待目录有点像个守财奴,它死守着目录,你创建它不会管(往里加),一但创建他就会监视该目录,若你要删除或重命名它的(动它的目录),它就发生重起了。。]
原因2:
文件夹选项中,如果没有打开“在单独的进程中打开文件夹窗口”,一旦新建一个窗口,系统可能认为是新的Session会话,而无法访问原来的Session,所以需要打开该选项,否则会导致Session丢失
原因3:
似乎大部分的Session丢失是客户端引起的,所以要从客户端下手,看看cookie有没有打开
原因4:
Session的时间设置是不是有问题,会不会因为超时造成丢失。
[默认时间是20分钟,可以在Web.Config中设置Session的timeOut,如改为60分钟等]
原因5:
IE中的cookie数量限制(每个域20个cookie)可能导致session丢失
原因6:
使用web garden模式,且使用了InProc mode作为保存session的方式
解决丢失的经验
1. 判断是不是原因1造成的,可以在每次刷新页面的时候,跟踪bin中某个文件的修改时间。
2. 做Session读写日志,每次读写Session都要记录下来,并且要记录SessionID、Session值、所在页面、当前函数、函数中的第几次Session操作,这样找丢失的原因会方便很多
3. 如果允许的话,建议使用state server或sql server保存session,这样不容易丢失
4. 在global.asa中加入代码记录Session的创建时间和结束时间,超时造成的Session丢失是可以在SessionEnd中记录下来的。
5. 如果有些代码中使用客户端脚本,如javascript维护Session状态,就要尝试调试脚本,是不是因为脚本错误引起Session丢失。 

 
转(3):Session丢失原因与解决方案小结 
可能的原因1:
win2003 server下的IIS6默认设置下对每个运行在默认应用池中的工作者进程都会经过20多个小时后自动回收该进程,造成保存在该进程中的session丢失。

因为Session,Application等数据默认保存在运行该Web应用程序的工作者进程中,如果回收工作者进程,则会造成丢失。

解决办法:
修改配置,设置为不定时自动回收该工作者进程,比如设置为当超出占用现有物理内存60%后自动回收该进程。通过使用默认应用程序池,可以确保多个应用程序间互相隔离,保证由于一个应用程序的崩溃不会影响另外的Web应用程序。还可以使一个独立的应用程序运行在一个指定的用户帐号特权之下。如果使用StateServer方式或者Sql Server数据库方式来保存Session,则不受该设置的影响。

可能的原因2:
系统要运行在负载平衡的 Web 场环境中,而系统配置文件web.config中的Session状态却设置为InProc(即在本地存储会话状态),导至在用户访问量大时,Session常经超时的情况。引起这个现象的原因主要是因为用户通过负载平衡IP来访问WEB应用系统,某段时候在某台服务器保存了Session的会话状态,但在其它的WEB前端服务器中却没有保存Session的会话状态,而随着并发量的增大,负载平衡会当作路由随时访问空闲的服务器,结果空闲的服务器并没有之前保存的Session会话状态。

解决办法: 
1.当您在负载平衡的 Web 场环境中运行 ASP.NET Web 应用程序时,一定要使用 SqlServer 或 StateServer 会话状态模式,在项目中我们基于性能考虑并没有选择SqlServer模式来存储Session状态,而是选择一台SessionStateServer 服务器来用户的Session会话状态。我们要在系统配置文件web.config中设置如下: 
<sessionState 
mode="StateServer" cookieless="false" timeout="240" 
stateConnectionString="tcpip=192.168.0.1:42424" stateNetworkTimeout="14400" /> 
还要添加一项 
<machineKey 
validationKey="78AE3850338BFADCE59D8DDF58C9E4518E7510149C46142D7AAD7F1AD49D95D4" decryptionKey="5FC88DFC24EA123C" validation="SHA1"/>  

2. 我们同时还要在SessionStateServer 服务器中启动ASP.NET State Service服务,具体设置:控制面板>>管理工具>>服务>>ASP.NET State Service,把它设为自动启动即可。 

3. 每台前端WEB服务的Microsoft“Internet 信息服务”(IIS)设置 
             要在 Web 场中的不同 Web 服务器间维护会话状态,Microsoft“Internet 信息服务”(IIS) 配置数据库中 Web 站点的应用程序路径(例如,\LM\W3SVC\2)与 Web 场中所有 Web 服务器必须相同。大小写也必须相同,因为应用程序路径是区分大小写的。在一台 Web 服务器上,承载 ASP.NET 应用程序的 Web 站点的实例 ID 可能是 2(其中应用程序路径是 \LM\W3SVC\2)。在另一台 Web 服务器上,Web 站点的实例 ID 可能是 3(其中应用程序路径是 \LM\W3SVC\3)。因此,Web 场中的 Web 服务器之间的应用程序路径是不同的。我们必须使Web 场Web 站点的实例 ID 相同即可。你可以在IIS中把某一个WEB配置信息保存为一个文件,其他Web 服务器的IIS配置可以来自这一个文件。您如果想知道具体的设置请访问Microsoft Support网站: 

 
转(4):丢失问题集锦 
SessionState 的Timeout),其主要原因有三种。
一:有些杀病毒软件会去扫描您的Web.Config文件,那时Session肯定掉,这是微软的说法。
二:程序内部里有让Session掉失的代码,及服务器内存不足产生的。
三:程序有框架页面和跨域情况。
第一种解决办法是:使杀病毒软件屏蔽扫描Web.Config文件(程序运行时自己也不要去编辑它)
第二种是检查代码有无Session.Abandon()之类的。
第三种是在Window服务中将ASP.NET State Service 启动。
http://community.csdn.net/Expert/topic/3100/3100218.xml?temp=.4426386
还有可能就是你在测试期间改动了,网站的文件。

下面是帮助中的内容:
(ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconsessionstate.htm)
ASP.NET 提供一个简单、易于使用的会话状态模型,您可以使用该模型跨多个 Web 请求存储任意数据和对象。
它使用基于字典的、内存中的对象引用(这些对象引用存在于 IIS 进程中)缓存来完成该操作。
使用进程内会话状态模式时请考虑下面的限制:
使用进程内会话状态模式时,如果 aspnet_wp.exe 或应用程序域重新启动,则会话状态数据将丢失。这些重新启动通常会在下面的情况中发生:
(1)在应用程序的 Web.config 文件的 <processModel> 元素中,设置一个导致新进程在条件被满足时启动的属性,例如 memoryLimit。
(2)修改 Global.asax 或 Web.config 文件。
(3)更改到 Web 应用程序的 \Bin 目录。
(4)用杀毒软件扫描并修改 Global.asax 文件、Web.config 文件或 Web 应用程序的 \Bin 目录下的文件。
(5)如果在应用程序的 Web.config 文件的 <processModel> 元素中启用了网络园模式,请不要使用进程内会话状态模式。否则将发生随机数据丢失。
 
我也碰到过。本机器上的Session或者Cookie丢失。
<sessionState
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
cookieless="false"
timeout="40"
/>
mode=""的三个属性。本地/其他机器/sqlserver。
很多网络架构,各个服务器之间都是通过一台专门保存状态的服务器(专门的状态服务器)来保存比如说session,cookie..
 
我以前遇到这种问题,我用了以下几个方法来解决。现在也没有这种情况发生了。
1、release,不要debug发布。
2、<sessionState cookieless="true" 把cookieless设为true。因为客户端禁用cookie时,session也无效。
3、在IIS中把Session过期时间延长。
4、让杀毒软件不扫描bin文件夹下的文件和Web.Config文件。
以上我是不明不白的做的。不过Session正常使用了!呵呵~~我幸运!
 
没啥好讲的,不要用Session好了,直接用Forms认证把,
我前两天的系统就是用这个搞定的,觉得挺好的。
刚碰到一个类似的问题:在使用frameset的时候,session变量丢失。
在微软的网站上找到了解决的方法
http://support.microsoft.com/kb/323752/EN-US/
不知道是否有用?

IIS--->>应用程序连接池--->>属性---->>[回收][性能][运行状况]里的各项参数尽量都往大的改^_^),我不知道改拉那个才对的,反正我改完后所有的session都好拉.客户的网站和动网论坛的后台也跟着好拉。 

 
转(5): 模态窗口中打开新窗口的session丢失 
         一直被这个问题郁闷。在窗口A中使用showModalDialog()打开了一个新的模态窗口B。然后在B窗口中进行一些业务操作,最后还需要根据业务操作打印一些表单,结果此时在B中调用open()方法就会出现session丢失的现象,提示用户重新登陆。
         两天来一直没头苍蝇一样不停的试验各种方法。如果在这个窗口中采用打开非模态对话框的打开方法showModelessDialog()就没有任何问题,但是直接使用open()方法就是不能达到想要的效果。在网上不停的google,到各大bbs寻找解答,提供的都是最简单的应用。好不容易找到一篇文章,其中提到session对象的有效范围,却也没有具体提到我遇到的问题:
IE中:
有效的窗品包括
         1.Session对象只在建立Session对象的窗口中有效。 
         2.在建立Session对象的窗口中新开链接的窗口无效的窗口包括
         1.直接启动IE浏览器的窗口
         2.不是在建立Session对象的窗口中新开链接的窗口。(即作者在建立Session对象的A窗口弹出的B窗口上调用了open()方法。)
考虑只在建立session对象的窗口中有效,于是就在子窗口中重新使用session.setAttribute()方法,以为如此就可以成功,结果还是不行,郁闷。
         早上起来突然来了灵感,既然子窗口中造成了session丢失,在父窗口中是无论如何还存在着session的变量的,我可以不必在子窗口中重新设置session变量,而可以直接调用父窗口的javascript函数open()方法可能会到目的吧。不管如何先试试,结果果然如此。   很多时候问题就是这样的,想要偷懒,于是不自己钻研,到处寻求解答,最后还是得靠自己来搞定。 

转载:http://blog.csdn.net/High_Mount/archive/2007/05/09/1601854.aspx