ASP.NET Trick文章系列--使用State Server管理Session状态的另类经济用法

       怎么使用Session本身的问题,这个就不必多说了吧。在这里就谈谈Session的管理机制。ASP.NET的优秀之处就在于它能充分利用整个.NET框架所提供的优秀的基础结构和底层操作,而大量设计模式的应用则大大加强了ASP.NET的可扩展性和可伸缩。当然在Session的管理方面.NET框架也同样为其提供了巨大的灵活性和可扩展性。

      ASP.NET为Session的管理提供了5种可选模式(基于Provider模型):1.不使用(Off),2.进程内(InProc),3.状态服务器(StateServer),4.SQLServer数据库(SQLServer),5.自定义(Custom)。默认情况下ASP.NET使用进程内模式管理Session状态。一般情况下基于小型应用的ASP.NET网站使用进程内管理Session状态已经足够了。如果我们需要在一个拥有多个子网站频道的大型网站中使用Session状态管理,那我们就需要考虑使用状态服务器或SQLServer的模式来管理Session的状态了。同样的需求也可能出现在负载均衡情况下的网站群集条件中。关于如何使用状态服务器或SQLServer的模式来管理大型网站的Session状态的介绍和使用详细在这里也就不具体介绍说明了,感兴趣的话可以参考MSDN文档或各位大牛的技术博文。^-^

     在一年前的一个项目中我遇到如此情景,项目是由一个主体频道站点和多个子频道站点组成。项目中有关用户的管理被设计到一个单独用户管理中心站点统一管理。鉴于之上的设计需求管理整个站点的Session状态我自然而然就想到需要使用状态服务器或SQLServer的模式来实现Session共享。于是参考了一段时间MSDN文档后决定使用状态服务器来实现(同时也由于项目本身自己的一些特点)。于是兴致勃勃的继续着之后的设计,但当项目即将交付的时候却被告知当前生产环境中只有三台服务器可供项目部署。由于当初参考MSDN文档的时候我清楚的记得使用状态服务器管理Session状态时,在IIS托管的网站及子网站都需要相同的网站标识符才能在状态服务器中定位正确的Session状态对象,而现在多个网站可能需要被部署到同一台机器的同一个IIS中,大家都知道每个IIS中的网站标识符都是唯一的。这下子我犯难了,于是苦思冥想了整整2天时间,最后想到了下面这个另类用法来解决此问题。

     由于框架为我提供的状态服务器模式不能满足我的要求,因此我需要使用自定义Session管理模式。用于拦截IIS向状态服务器请求的消息,模拟所有频道站点的请求都使用相同的网站标识符。在这里我按照Session管理的提供者扩展模型实现了一个自定义的Session管理类,用来给系统提供的状态服务器管理类做一个对象适配,在内部同过反射技术来创建一个System.Web.SessionState.OutOfProcSessionStateStore类的对象实例并修改对象的部分属性来满足项目的需求,代码类定义如下:

ContractedBlock.gif ExpandedBlockStart.gif Code
//本类使用对象适配器模式修改系统默认设置,使单个IIS中多个应用程序共用同一状态session
    public class CustomOutOfProcSessionStateStore : SessionStateStoreProviderBase
ExpandedBlockStart.gifContractedBlock.gif    
{
        
private SessionStateStoreProviderBase _sessionStateStore = null;

        
public OutOfProcSessionStateStore()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Assembly assembly 
= Assembly.GetAssembly(typeof(System.Web.SessionState.HttpSessionState));
            _sessionStateStore 
= 
                (SessionStateStoreProviderBase)assembly.CreateInstance(
"System.Web.SessionState.OutOfProcSessionStateStore");
        }


        
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _sessionStateStore.Initialize(name, config);

            Type storeType 
= _sessionStateStore.GetType();
            
//系统指定默认路径变量名称
            string baseUriName = "s_uribase";
            
//获取系统默认路径设置
            string oldBaseUri = (string)storeType.InvokeMember(baseUriName, 
                BindingFlags.GetField 
| BindingFlags.NonPublic | BindingFlags.Static,
                
null
                
null
ExpandedSubBlockStart.gifContractedSubBlock.gif                
new object[] { }
                );
            
//指定系统ApplicationId,这里的888就是IIS中的网站标识符
            string appId = "/LM/W3SVC/888/ROOT";
            
//获取配置加密key
            string hashKey = (string)typeof(System.Web.Configuration.MachineKeySection).InvokeMember("HashAndBase64EncodeString"
                BindingFlags.InvokeMethod 
| BindingFlags.NonPublic | BindingFlags.Static,
                
null
                
null
ExpandedSubBlockStart.gifContractedSubBlock.gif                
new object[] { appId }
                );
            
//获取新的session检索基路径
            string newBaseUri = appId + "(" + hashKey + ")/";
            
//修改系统默认路径设置
            storeType.InvokeMember(baseUriName,
                BindingFlags.SetField 
| BindingFlags.NonPublic | BindingFlags.Static, 
                
null
                
null
ExpandedSubBlockStart.gifContractedSubBlock.gif                
new object[] { newBaseUri }
                );

            
base.Initialize(name, config);
        }


        
public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return _sessionStateStore.CreateNewStoreData(context, timeout);
        }


        
public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _sessionStateStore.CreateUninitializedItem(context, id, timeout);
        }


        
public override void Dispose()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _sessionStateStore.Dispose();
        }


        
public override void EndRequest(HttpContext context)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _sessionStateStore.EndRequest(context);
        }


        
public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return _sessionStateStore.GetItem(context, id, out locked, out lockAge, out lockId, out actions);
        }


        
public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return _sessionStateStore.GetItemExclusive(context, id, out locked, out lockAge, out lockId, out actions);
        }


        
public override void InitializeRequest(HttpContext context)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _sessionStateStore.InitializeRequest(context);
        }


        
public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _sessionStateStore.ReleaseItemExclusive(context, id, lockId);
        }


        
public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _sessionStateStore.RemoveItem(context, id, lockId, item);
        }


        
public override void ResetItemTimeout(HttpContext context, string id)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _sessionStateStore.ResetItemTimeout(context, id);
        }


        
public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _sessionStateStore.SetAndReleaseItemExclusive(context, id, item, lockId, newItem);
        }


        
public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return _sessionStateStore.SetItemExpireCallback(expireCallback);
        }

    }

    

     整个类中最重要的方法是Initialize方法,其他的只是做一下简单的对象方法适配以保证和框架提供的类保持相同的逻辑功能。其实在整个拦截过程中我们只需要修改baseUriName的值,如何修改baseUriName的值已经在类的方法定义中做了注释说明,大家可以参照类型定义了解详细。

     类型定义好以后我们需要做的代码工作就完毕了,接下来要做的只是把这个类型引入到各个频道站点项目下,当然也可以直接把类型复制到AppCode目录下,也可以把它单独放在一个程序集中单独编译并引用到各个频道站点项目下。 接下我们需要做的工作就是修改各个站点下Web.Config文件中的Session配置节点,配置如下:

< sessionState 
    mode
= " Custom "  
    cookieless
= " false "  
    timeout
= " 15 "  
    stateConnectionString
= " tcpip=ip:端口 "  
    customProvider
= " OutOfProcSessionProvider "  
    stateNetworkTimeout
= " 300 " >
    
< providers >
       
< add name = " OutOfProcSessionProvider "  type = " CustomOutOfProcSessionStateStore " />
    
</ providers >
</ sessionState >

 

在这里特别要注意的是我们还需要添加machineKey配置节用来在Initialize方法中使用相同的key值重新加密解密ApplicationId。

< machineKey  
 validationKey
= " 78AE3850338BFADCE59D8DDF58C9E4518E7510149C46142D7AAD7F1AD49D95D4 "   
 decryptionKey
= " 5FC88DFC24EA123C "
 validation
= " SHA1 " />

 

最后在各个站点中执行相同的配置过程就可以实现同一IIS中用状态服务器模式实现Session状态共享了。^-^

当然如果以后条件许可下,我们只需要简单的修改下配置就能把Session管理还原到框架提供的状态服务器管理模型中,非常之方便!

 

转载于:https://www.cnblogs.com/igtea/archive/2009/02/03/1382825.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值