zoukankan      html  css  js  c++  java
  • 纠结的Session备忘

    使用中的问题: 

    一个Asp.net的CRM项目在Session中存储自定义类型(可序列化的),开始使用的是InProc方式,几个月过去了一切都很和谐,但是最近随着使用人数的增加进程内Session经常丢失,于是业务员就很郁闷,好在MS提供了SqlServer与StateServer,这样可以在数据库或状态服务中保存Session,我只化了3分时间就把Web.config中的配置调整成StateServer方式,本以为这样就天下太平了,结果发现我错了,系统运行一段时间(或者说一个用户登录后点个7,8下)就会报错,错误点是SessionStateItemCollection.Deserialize。再接下来的时间里我想了各种办法来解决这个问题,我甚至将自定义类型,先使用xml序列化成字符串后再保存到Session里这样Session里保存的就是简单的string类型了,结果问题依旧,最后试了SqlServer方式,依然失败。 现阶段是将一些短数据放到cookie里,其他长数据在使用时从数据库中加载,好在当时对存储在Session里的数据存取进行了简单的封装,页面里没有直接使用Session["xx"]=yy; 这样的代码,不然项目里200多个并且出自4个程序员之手的页面改起来够崩溃了。

    程序里主要代码如下:

    public class UserSetting{

      public static T LoadSession<T>(string key) where T:class{

        return HttpContext.Current.Session[key] as T;

       }

         public static void SaveSession<T>(string key, T data)where T:class
          {
                HttpContext.Current.Session[key] = data;

           }

        //........其他属性

    }

    保存在Session里的自定义类型如下:

    ISerializable的代码,多是基本类型

           #region ISerializable 成员

           public void GetObjectData(SerializationInfo info, StreamingContext context)
           {
               info.AddValue("Code",Code);
               info.AddValue("CurrentAuthType", CurrentAuthType);
               info.AddValue("IsRegionalManager", IsRegionalManager);
               info.AddValue("IsSalesman", IsSalesman);
               info.AddValue("AreaName", AreaName);
               info.AddValue("EmployeId", EmployeId);
               info.AddValue("AreaId", AreaId);
               info.AddValue("CurrentRole", CurrentRole);
               info.AddValue("Name", Name);
           }
           private UserSessionData(SerializationInfo info, StreamingContext context)
           {
               Code = info.GetString("Code");
               CurrentAuthType = info.GetInt32("CurrentAuthType");
               IsRegionalManager = info.GetBoolean("IsRegionalManager");
               IsSalesman = info.GetBoolean("IsSalesman");
               AreaName = info.GetString("AreaName");
               EmployeId = info.GetInt32("EmployeId");
               AreaId = info.GetInt32("AreaId");
               CurrentRole = info.GetString("CurrentRole");
               Name = info.GetString("Name");
           }

           #endregion

    进程内Session运行正常,stateSever,跟SqlServer Session运行总会出现如下错误,

    寻思了一阵子还是解决不了,目前打算自己实现个简单的Session,于是就开始了解asp.net Session的实现方式

    Session机制的基本描述

    Http是无状态的,Asp.net 会在用户访问具体.aspx页面时写个Asp.net_SessionId:xxxxxxxxxxx的cookie到客户端的浏览器中(也可以通过url方式),这样客户浏览器以后发起的每个请求都会带上这个cookie数据(可以通过火狐的fireBug中的网络观察到),asp.net利用从Asp.net_SessionId字段中获取的数据,也就是"xxxxxxxxxxx"到Session数据存储区(InProc,SqlServer,StateServer)检索对应的数据,然后构造出Session相关对象,供客户程序访问,具体一点的说就是通过SessionStateModule注册HttpApplication生命周期中的AcquireRequestState与ReleaseRequestState事件,分别将数据存储区的数据读出反序列化后附加到访问HttContext.Session上,以及将HttContext.Session数据序列化后保存到数据存储区中,而对数据存储区的读写由实现了SessionStateStoreProviderBase的类完成(Asp.net的提供程序模型)。

    涉及的主要类

    Session工作的基本流程

    注意:这个流程图我参考相关资料大致画的,打算自己按这个方式实现一个MySession,不是微软Session的完整流程,MS的那个代码涉及面太多了,本人水平有限没完整理清。

    上图中有个IRequiresSessionState类型是一个标记接口,用来告诉SessionStateModule是否要给当前请求构建立Session对象,一般站点上对.jpg,.png.html等资源的请求是不会发给asp.net来处理的,但是如果你配置了IIS,或者采用MVC建立应用程序时,对这些资源的请求都会发给asp.net的,如果跟踪请求会发现有大量图片的页面在打开时会有大量的ResetTimout操作出现,影响性能,这个时候可以将具体的资源目录(如/images)转化成虚拟目录,并取消静态资源到asp.net处理程序的映射

    Session的锁定机制

    Session数据是一个浏览器一份的(默认采用Httponley cookie来保存SessionId)数据间各自独立,但是如果网站中使用框架,或ajax中并行发起请求,就可能出现Session访问并发问题,Asp.net采用的机制是针对两个并发的请求(携带同一个SessionID),asp.net会根据SessionID去锁定Session数据存储中的对应记录,直到HttpAplication的ReleaseRequestState阶段释放锁定,而这个时候另外一个并非请求会被阻塞,并且每隔半秒再尝试一次直到超时或锁定成功。

    Asp.net程序中,一个请求会由一个HttpApplication类应答,一个HttpApplication同一时间只处理一个请求,但是会有多个HttpApplication存在,以提供对网站并发访问请求的处理,HttpApplication是可以重复利用的,每个HttpApplication中都有一组独立的HttpModule,HttpApplication对象在被第一次创建时会根据配置建立自己的HttpMoudle集合,并调用每个HttpModule的Init方法,而每个HttpApplication再次被使用时(除创建那次外),不会再次构建HttpModule集合,当然也不会调用注册的HttpModule的Init方法了,这点在实现SessionStateModule时需要注意,内存结构参考下图:

    Session的序列化

    Session中的数据采用BinaryWriter,BinaryReader进行读写,具体在声明成internal的System.Web.Util.AltSerialization中实现,
    Session数据最终按: [数据类型编号1][数据长度][数据][数据类型编号2][数据]...这样的方式存在成二进制格式,需要注意的是当[数据类型编号]是int,long这些长度已知的数据类型时[数据长度]是不写入的,另外自定义类型由BinaryFormatter类对流进行读写,代码截图如下:

    一些参考网地址:

    ASP.NET 2.0 异步页面原理浅析 [1]

    如何:演示会话状态存储提供程序

  • 相关阅读:
    hdu 1042 N!
    hdu 1002 A + B Problem II
    c++大数模板
    hdu 1004 Let the Balloon Rise
    hdu 4027 Can you answer these queries?
    poj 2823 Sliding Window
    hdu 3074 Multiply game
    hdu 1394 Minimum Inversion Number
    hdu 5199 Gunner
    九度oj 1521 二叉树的镜像
  • 原文地址:https://www.cnblogs.com/wdfrog/p/2042795.html
Copyright © 2011-2022 走看看