(1)建立存放 Session 的 DataBase
打开Visual Studio 命令提示工具执行下面的命令,此命令会创建存储Session的数据库ASPState、清除过期Session的作业,以及相应的一些存储过程。
D:/Microsoft Visual Studio 9.0/VC>aspnet_regsql -S 192.168.4.188 -U sa -P dianji
an@2010 -ssadd -sstype p
会话数据保存在指定的SQLServer数据库中,会话数据通过SessionID进行查找,理论上只需要使多个站点共享同一会话数据库即可共享会 话数据,确定了思路便好办。多个站点共享统一会话数据库在.NET下是很容易的事情,只需要在WEB.CONFIG里配置sessionState节点指 定会话存储模式以及相同的会话数据库即可。事情没有这么简单,不同的站点其SessionID是不同的,就算SessionID相同了,保存在会话数据库 中的实际SessionID的值也不只是网站生成的SessionID,而是在SessionID后加上了站点的AppName,因此即使各个站点共享了 会话数据库也不能共享会话数据。打开会话数据表ASPStateTempSessions中的记录,可以发现如下几个数据
ASPStateTempSessions各个字段的意义如下:
表1 ASPStateTempSessions表
列 | 类 型 | 描 述 |
SessionId | char(88) | 索引字段,它表示会话ID |
Created | DateTime | 指出会话被创建的时间。默认值为当前时间 |
Expires | DateTime | 指出会话将到期的时间。该值一般等于会话状态的创建时间加上Timeout中指定的分钟数。注意,Created指会话的创建时间,而 Expires把分钟数加到第一个数据项被添加到会话状态的时间 |
LockDate | DateTime | 指出会话被锁定以添加最后一个数据项的时间。该值表示为当前的UTC(Universal Time Coordinate)时间 |
LockDateLocal | DateTime | 与LockDate一样,但是它只表示系统的本地时间。ASP.NET 1.x不支持该列 |
LockCookie | int | 指出该会话被锁定的次数——即,访问次数 |
Timeout | int | 指出会话的超时时间(以分为单位) |
Locked | bit | 指出会话当前没有被锁定 |
SessionItemShort | VarBinary(7000) | 可以取null的字段。它表示指定会话中的值。这些字节的布局等同于StateServer提供程序所述的布局。如果对字典进行序列化需要7000 多字节,则使用SessionItemLong |
SessionItemLong | Image | 可以取null的字段,表示一个超过7000字节的会话状态的序列化版本 |
Flags | Int | 指示SessionStateActions枚举类型的行动标记(初始化数据项)。ASP.NET 1.x不支持该列 |
其中的SessionId包括两个部分:网站生成的24位SessionID及8位 AppName(这个AppName是怎么来的呢?)对于不同的站点,其AppName不同,在能够在不同站点下使24位SessionID相同的情况 下,要保证经过组合加上AppName后的SessionID相同,可以通过修改存储过程TempGetAppID,使其得到的SessionID与 AppName无关,修改TempGetAppID如下:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

经过以上修改之后,下面要实现多个站点共用同一个SessionID,对 ASP.NET的会话模型System.Web.SessionState.SessionIDManager.GetSessionID(HttpContext context)方法进行反编译,分析其源代码:
2 {
3 string id = null ;
4 this .CheckInitializeRequestCalled(context);
5 if ( this .UseCookieless(context))
6 {
7 return ( string ) context.Items[ " AspCookielessSession " ];
8 }
9 HttpCookie cookie = context.Request.Cookies[Config.CookieName];
10 if ((cookie != null ) && (cookie.Value != null ))
11 {
12 id = this .Decode(cookie.Value);
13 if ((id != null ) && ! this .ValidateInternal(id, false ))
14 {
15 id = null ;
16 }
17 }
18 return id;
19 }
20
21
22
可 以看到,SessionID是通过客户端的Cookie进行保存的,因此,只要使各个站点共用同一个Cookie文件保存SessionID即可达到目 的。如何使不同的站点共用同一个Cookie呢?只要设置cookie.Domain为相同的域即可。在页面的PageLoad事件中加上以下代码:
2 cookie.Domain = ".websitename.com";
3 cookie.Expires = DateTime.Now.AddDays( 365 ); //设置Cookie保存的天数,不可少于1天
4 HttpContext.Current.Response.Cookies.Add(cookie);
经过以上步骤之后,终于真正的实现了多站点会话共享。
二.
和上面前面一样.在WEB.CONFIG里配置sessionState节点指定会话存储模式以及相同的会话数据库.由上面第一种方法分析可以知 道.AppName不一样.上面是让它忽略AppName.下面就是让他AppName一样.这样也能达到同样效果.具体做法是:
在每个子站点必须设置相同路径主目录(比如.有三台服务器.WEB程序IIS主目录都应指向同一位置.如都在D:/WebRoot下)
这样.AppName会得一个相同的值.
注意 :如果你是在已经建立好的IIS站点上.采用这种模式.建议选删除原来的 WEB站点.再新建成每台都一样的物理路径的IIS站点.我的理解是.一但建立就生成了AppName.以后修改它是不会变的(不知道是不是这个原因,但 我就是这样才解决的.删除其它已建立好的.重新建立的),所以保证真正的AppName一样.得严格按照上面的做法.
(2)设置 Web.config 内容
打开 Web.config → 找到 <sessionState> 节点内容 → 修改为以下内容即可:
<sessionState mode="SQLServer" sqlConnectionString ="data source=192.168.0.2; user id= sa; password=123456" timeout="20" />
(3)开启作业ASPState_Job_DeleteExpiredSessions,及时的清空过期Session