Session丢失总结 - 删除文件



---------------------------------------------
2012-4-21
--------------------------------------------- 

/*******************************************
Web.Config  
*******************************************/
<system.web>
    <httpModules>
      <add name="stopAppDomainRestartOnFolderDelete" type="PG.Web.StopAppDomainRestartOnFolderDeleteModule,PG.Web"/>
    </httpModules>

</system.web>



/*******************************************
StopAppDomainRestartOnFolderDeleteModule.cs  
*******************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Web;


namespace PG.Web
{
    public class StopAppDomainRestartOnFolderDeleteModule : IHttpModule
    {
        private static bool DisableFCNs = false;
        public void Init(HttpApplication context)
        {
            if (DisableFCNs) return;
            PropertyInfo p = typeof(HttpRuntime).GetProperty("FileChangesMonitor", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
            object o = p.GetValue(null, null);
            FieldInfo f = o.GetType().GetField("_dirMonSubdirs", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
            object monitor = f.GetValue(o);
            MethodInfo m = monitor.GetType().GetMethod("StopMonitoring", BindingFlags.Instance | BindingFlags.NonPublic);
            m.Invoke(monitor, new object[] { });
            DisableFCNs = true;
        }
        public void Dispose() { }
    }
}






-------------------------------------------

也许你知道,修改站点的某些特定文件和目录会导致整个站点重启或者重新编译。也许你不注意,你不会知道删除或重命名站点下的任意目录,会导致整个站点重启(添加目录并不会)。这个问题其实是很多Session丢失的根源,比如《关于ASP.NET 2.0的目录结构变化导致Session丢失的问题》,同样你还可以找到很多这样的例子。

这个其实是ASP.NET 2.0的一个“精心”设计,因为在很多情况下。ASP.NET会缓存很多资源,而如果没有监控目录的变动的话,那么有些已删除的资源就有可能仍然被使用着,造成其它不必要的资源泄露。通过这篇文章我们可以找到可能导致站点重启的一些条件,其中的第一条就是删除或重命名目录会导致站点重启。

这个问题早在ASP.NET 2.0刚发布的时候就被发现,并且已经有了专门的讨论《Deleting ASP.NET 2.0 Application Sub-Directories Shuts Down the AppDomain》,在文中也提了一种解决方案,但是做法太过复杂。最理想的方案是,有相关的补丁来解决这个问题,幸运的是,我们可以通过这里找到这个补丁,并且介绍如何配置来解决这个问题。

解决方案是:监控目录删除或重命名的机制叫:File Change Notifications (FCNs),这个补丁就是用来设置FCNS禁用或启用的开关,我们只要把FNCS禁用就可以避免这个问题。

做法:现在的ASP.NET 2.0已经到了SP2,我们不需要单独去安装这个补丁。我们只需要在注册表在做一步操作即可解决这个问题。在HKLM\Software \Microsoft\ASP.NET 添加一个名为:FCNMode 的DWORD值,默认它应该是不存在的,它的值含义为:

Does not exist
This is the default behavior. For each subdirectory, the application will create an object that will monitor the subdirectory.

0 or greater than 2
This is the default behavior. For each subdirectory, the application will create an object that will monitor the subdirectory.

1
The application will disable File Change Notifications (FCNs).

2
The application will create one object to monitor the main directory. The application will use this object to monitor each subdirectory.

我们将它的值设为1即可禁用FCNS。更为详细的可以参考:http://support.microsoft.com/kb/911272

退出注册表,重启IIS,问题即可解决。

说明一下:Session丢失只是AppDomain重启的一个副作用,并不是本文的重点,只是为了方便别人查找相关问题时的一个标题优化。另外导致站点重启的原因有很多种,可以参考上文给出的链接,这里不再遨述。


-------------------------------------------

最简单的办法就是不要使用默认的方式也即 
InProc(默认,进程内的会话状态):Session存储在IIS进程中(Web服务器内存)。如果使用的是Windows 2000 Server或Windows XP,IIS使用aspnet_wp.exe进程,如果使用的是Windows 2003 Server,IIS使用w3wp.exe。 

InProc拥有最好的性能。但进程内Session很容易丢失Session信息。如果重启了应用程序,所有的Session信息就会丢失。而很多原因都会导致ASP.NET应用程序的重启。 
 修改了Web.Config或Global.asax文件,或改变了文件的修改日期。 
 修改了\bin或\App_Code目录里的文件。 
 防病毒软件修改了上述文件等等 

你可以考虑以下两种方式 
1、StateServer(进程外的会话状态):Session存储在独立的Windows服务进程aspnet_state.exe中 

如果要启用StateServer中的Session状态,首先要在”控制面板”--“管理工具”--“服务”中,启用ASP.NET State Services(ASP.NET 状态服务),并将此服务设置为Automatic(自动启动) 

启动ASP.NET状态服务后,需要配置ASP.NET应用程序来使用它。 
我们需要在Web.Config文件中system.web节点中添加如下代码 
<sessionState mode="StateServer" stateNetworkTimeout="20" 
stateConnectionString="tcpip=127.0.0.1:42424" /> 
首先,mode属性被设为StateServer。接着,stateConnectionString属性用来指定ASP.NET状态服务器端的位置。连接位置被创建为在127.0.0.1,端口42424。最后,stateNetworkTimeout属性用来指定连接超时的秒数。 
需要注意的是,此时必须把对象标注为可序列化后(使用Serializable特性标记需要序列化的类)才能在服务中进行存储。Microsoft建议所有的开发人员在开发过程中都使用进程外的会话状态,以避免项目如果切换到其他进程外的提供程序或SqlServer而导致站点的错误。 

或者使用 
2、SqlServer:Session存储在SqlServer数据库的表中,可以用aspnet_regsql.exe配置它(SqlServer服务器)

还一种办法是釆用虚拟目录的方法:

前提是你有再web(项目文件夹)站点下建立虚拟目录的权限,并且可以将虚拟目录指定到web文件夹外部

比如应用程序的上传文件夹是/Uploadfiles,那么需要在IIS中给web站点下面建立一个Uploadfiles虚拟目录,并指向web文件夹外部的另一个文件夹。

并且删除web下面的uploadfiles物理目录

这样子就可以绕过修改web文件结构而引起session丢失的问题,实现删除文件夹而不会引起应用程序重启


-------------------------------------------


如果你曾经修改了ASP.NET应用程序(dll文件),与修改了bin文件夹或Web.config文件(添加/删除/重命名的文件等),而该网站在运行,你可能已经注意到,这将导致在AppDomain的重新启动。所有的会话状态会丢失和网站再次成功启动,任何登录的用户将被退出(假设你不使用持久Cookie身份验证)。 当然,当我们修改了web.config文件,并保存它,迫使一个AppDomain重新启动,这是我们需要的。 


我们有时动态创建和删除的文件夹,在ASP.NET 2.0中,文件夹删除将导致一个AppDomain重新启动,这将导致严重的问题。 例如,对于一个电子商务网站的产品,你可能想存储在目录中的产品来自它的名字ID的产品的图片,例如。/ productImages/123/ipod-nano.jpg,甚至为身份证图像的记录。 这有助于避免与其他上载的文件和图像文件名冲突。 当然,当你来到删除从数据库产品,你自然要删除其相应的图像和含有它的文件夹,但显然不能因为这AppDomain重新启动的问题。 因为,我们删除留在我们的服务器中的空文件夹(文件删除不会引起应用程序重新启动)。 


解决方案 


幸运的是,我们有了Reflection and HttpModules的解决方案。 首先创建一个像.cs文件... 


复制代码 代码如下:


using System.Reflection; 

using System.Web; 

namespace MyWebsite 

/// <summary> 

/// Stops the ASP.NET AppDomain being restarted (which clears 

/// Session state, Cache etc.) whenever a folder is deleted. 

/// </summary> 

public class StopAppDomainRestartOnFolderDeleteModule : IHttpModule 

public void Init(HttpApplication context) 

PropertyInfo p = typeof(HttpRuntime).GetProperty("FileChangesMonitor", 

BindingFlags.NonPublic BindingFlags.Public BindingFlags.Static); 

object o = p.GetValue(null, null); 

FieldInfo f = o.GetType().GetField("_dirMonSubdirs", 

BindingFlags.Instance BindingFlags.NonPublic BindingFlags.IgnoreCase); 

object monitor = f.GetValue(o); 

MethodInfo m = monitor.GetType().GetMethod("StopMonitoring", 

BindingFlags.Instance BindingFlags.NonPublic); 

m.Invoke(monitor, new object[] { }); 

public void Dispose() { } 



如果您喜欢在 Application_Start使用Global.asax文件中,放置在Init()代码在Application_Start 中。 我相信在Global.asax使用方法已过时,在使用HttpModules可以响应网络(应用程序生命周期的会话开始,会话结束时,)。 init方法在Global.asax同Application_Start作用是一样的,Dipose类似于Application_End。 


我们要以上述代码起作用,需要在web.config文件<httpModules>区段中放入: 


<add name="stopAppDomainRestartOnFolderDelete" 

type="MyWebsite.StopAppDomainRestartOnFolderDeleteModule" /> 

需要说明的是,"stopAppDomainRestartOnFolderDelete"为自定义的任意名称,"MyWebsite"为上述.cs文件中的命名空间,一般为项目名称."StopAppDomainRestartOnFolderDeleteModule"为上述.cs文件中的类名. 


这就是它。 这将防止文件夹删除AppDomain重新启动,但修改web.config和bin文件夹时仍会重新启动,这正是我们想要的。 


但是多删除几个文件就会发现 session 还是会过期,为什么会是这样的呢?现在还没搞清楚...于是在网上搜索就有了下面的这种方式 


在 <system.web>下面配置 session 的保存方式为stateserver就可以了 


< session State mode="StateServer" stateNetworkTimeout="20" 

stateConnectionString="tcpip=127.0.0.1:42424" /> 

参数一看就知道是什么意思了.. 

本文来自【中迎网络】http://www.shwebzy.com/   原文地址:http://www.shwebzy.com/blog-767.aspx




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值