ASP.NET中Session跨站点共享实现方式

一、安装session数据库

使用VS自带的命令工具 到 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 目录下面使用命令

例如:aspnet_regsql.exe -ssadd -sstype c -d [DB] -S [Server] –E (使用相应命令可以对远程数据库进行创建)

具体参数说明参考:http://msdn.microsoft.com/zh-cn/library/ms229862(VS.80).aspx

其实使用的是文件夹下面的:InstallSqlState.sql 与InstallPersistSqlState.sql 前一个是在temp数据库中,重启数据库将会session丢失,后一个在独立数据库中,重启数据库session不会丢失

但是在数据库中直接使用这两个文件进行创建将会出现错误,不知道代理服务开始时候还会出现,但是使用命令就算代理服务没有开启也是可以创建的

二、配置web.config

<sessionState mode="SQLServer" sqlConnectionString="data source=[Server];initial catalog=[DB];user cookieless="false" timeout="60"></sessionState>

三、修改数据库存储过程

通过以上配置session已经保存在数据库中,但是不同的站点其SessionID是不同的,就算SessionID相同了,保存在会话数据库中的实际SessionID的值也不只是网站生成的SessionID,而是在SessionID后加上了站点的AppName,因此即使各个站点共享了会话数据库也不能共享会话数据。

CREATE PROCEDURE dbo.TempGetAppID

@appName tAppName,

@appId int OUTPUT

AS

SET @appName = LOWER(@appName)

SET @appId = NULL

SELECT @appId = AppId

FROM [JSEC_SessionDB].dbo.ASPStateTempApplications

WHERE AppName = @appName

IF @appId IS NULL BEGIN

BEGIN TRAN

SELECT @appId = AppId

FROM [JSEC_SessionDB].dbo.ASPStateTempApplications WITH (TABLOCKX)

WHERE AppName = @appName

IF @appId IS NULL

BEGIN

EXEC GetHashCode @appName, @appId OUTPUT

INSERT [JSEC_SessionDB].dbo.ASPStateTempApplications

VALUES

(@appId, @appName)

IF @@ERROR = 2627

BEGIN

DECLARE @dupApp tAppName

SELECT @dupApp = RTRIM(AppName)

FROM [JSEC_SessionDB].dbo.ASPStateTempApplications

WHERE AppId = @appId

RAISERROR('SQL session state fatal error: hash-code collision between applications ''%s'' and ''%s''. Please rename the 1st application to resolve the problem.',

18, 1, @appName, @dupApp)

END

END

COMMIT

END

RETURN 0

GO

修改以上第五行 set @appName='XXX' 任意值使每个站点使用相同的appName

四、修改Cookie保存方式确保cookie使用相同主域

public class CrossDomainCookie : IHttpModule

{

private string m_RootDomain = string.Empty;

#region IHttpModule Members

public void Dispose()

{

}

public void Init(HttpApplication context)

{

m_RootDomain = ConfigurationManager.AppSettings["RootDomain"];

Type stateServerSessionProvider = typeof(HttpSessionState).Assembly.GetType("System.Web.SessionState.OutOfProcSessionStateStore");

FieldInfo uriField = stateServerSessionProvider.GetField("s_uribase", BindingFlags.Static | BindingFlags.NonPublic);

if (uriField == null)

throw new ArgumentException("UriField was not found");

uriField.SetValue(null, m_RootDomain);

context.EndRequest += new System.EventHandler(context_EndRequest);

}

void context_EndRequest(object sender, System.EventArgs e)

{

HttpApplication app = sender as HttpApplication;

for (int i = 0; i < app.Context.Response.Cookies.Count; i++)

{

app.Context.Response.Cookies[i].Domain = m_RootDomain;

}

}

#endregion

}

以上参考:

http://www.cnblogs.com/jzywh/archive/2008/11/02/sharesession.html

五、修改web.config

<appSettings>

<add key="RootDomain" value=".test.com"/>

</appSettings>

<system.web>

<machineKey decryptionKey="FD69B2EB9A11E3063518F1932E314E4AA1577BF0B824F369" validationKey="5F32295C31223A362286DD5777916FCD0FD2A8EF882783FD3E29AB1FCDFE931F8FA45A8E468B7A40269E50A748778CBB8DB2262D44A86BBCEA96DCA46CBC05C3" validation="SHA1" decryption="Auto"/>

<sessionState mode="SQLServer" sqlConnectionString="data source=[Server];initial catalog=[DB];user cookieless="false" timeout="60"></sessionState>

<httpModules>

<add name="CrossDomainCookieModule" type="Test.HttpModule.CrossDomainCookie, GB87.HttpModule"/>

</httpModules>

</system.web>

<system.webServer>

<modules>

<add name="CrossDomainCookieModule" preCondition="managedHandler" type="Test.HttpModule.CrossDomainCookie, GB87.HttpModule" />

</modules>

</system.webServer>

以上完成了 所有的配置

接下来就是配置在IIS上面 创建两个网站 http://www.test.com/ http://a.test.com/

并修改host文件 指向127.0.0.1 进行测试 通过测试

配置使用过程中发现的问题:

在使用session保存对象的时候一定要能够序列化,类名前面加[Serializable],而且在我测试的时候两个网站没有使用相同的实体层,实体层的名字不同造成无法转化的问题

其他参考:

http://hi.baidu.com/hiqb/blog/item/1b935fee2878b3f7b2fb9542.html

http://www.cnblogs.com/leonsky/articles/1427014.html