为什么我不能在两个使用StateServer的Web应用程序之间共享会话状态? 我错过了什么?

我无法使用Session StateServer获得两个相同的ASP.NET MVC应用程序来共享同一个Session。 我试图这样做的原因是我们最终将在3个需要共享相同状态的Web服务器上部署此应用程序。 我们需要使用StateServer,因为我们正在尝试最小化数据库对非数据相关存储的使用。

设置:

我已经将相同的代码库部署到http:// localhost / App1和http:// localhost / App2

两者都具有相同的Web.Config文件,具有以下内容:

  //stateConnectionString="tcpip=192.168.1.52:42424" /> // also doesn't work  

我用这个工具生成这些机器密钥

考试:

我将以下内容放入我的一个控制器中以测试它是否正常工作:

 ViewData["mode"] = requestContext.HttpContext.Session.Mode.ToString(); string timestamp = DateTime.Now.ToString(); if (requestContext.HttpContext.Session["timestamp"] == null) { requestContext.HttpContext.Session["timestamp"] = timestamp; } ViewData["timestamp"] = requestContext.HttpContext.Session["timestamp"].ToString(); ViewData["realtime"] = timestamp; 

在视图中有这个:

 

Mode:

Time:

real time:

结果:

对于这两个部署,当页面首次加载时,我可以看到模式是StateServer,时间戳设置为与实时值相同的时间。但是,如果这样做,只有第一页应该具有相同的时间实时价值。 第二个页面加载应该从StateServer读取,因为该时间戳值不再为null,并显示该时间值。 但相反,它再次显示实时价值。

刷新页面时,时间戳保持不变,实时值始终更新。 这表示时间戳正在保存到会话中,但是当两个部署应该相同时,时间戳值始终不同,因此这表示会话未被共享。

有人可以指出,如果我做错了什么,或者我还需要做些什么才能让它发挥作用? 谢谢

默认情况下,不能在不同应用程序之间共享会话。 从我所看到的,你有两个不同的应用程序App1App2 ,它们运行在不同的虚拟目录中,甚至可能是独立的应用程序池,所以不要指望它们之间共享会话。

与往常一样,您可能会发现有用的变通方法 。 正如你所看到的那样,它正在使用hack(reflection)来绕过ASP.NET团队设计师决心不暴露某些类和属性,并使我们的生活变得困难。

实际上,您可以使用Sql server模式共享会话。

试试这个:-

我只是改变了程序,即

 USE ASPState GO ALTER PROCEDURE dbo.TempGetAppID @appName tAppName, @appId int OUTPUT AS -- start change -- Use the application name specified in the connection for the appname if specified -- This allows us to share session between sites just by making sure they have the -- the same application name in the connection string. DECLARE @connStrAppName nvarchar(50) SET @connStrAppName = APP_NAME() -- .NET SQLClient Data Provider is the default application name for .NET apps IF (@connStrAppName <> '.NET SQLClient Data Provider') SET @appName = @connStrAppName -- end change SET @appName = LOWER(@appName) SET @appId = NULL SELECT @appId = AppId FROM [ASPState].dbo.ASPStateTempApplications WHERE AppName = @appName IF @appId IS NULL BEGIN BEGIN TRAN SELECT @appId = AppId FROM [ASPState].dbo.ASPStateTempApplications WITH (TABLOCKX) WHERE AppName = @appName IF @appId IS NULL BEGIN EXEC GetHashCode @appName, @appId OUTPUT INSERT [ASPState].dbo.ASPStateTempApplications VALUES (@appId, @appName) IF @@ERROR = 2627 BEGIN DECLARE @dupApp tAppName SELECT @dupApp = RTRIM(AppName) FROM [ASPState].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 

然后将web.config修改为: –

   

您必须添加应用程序名称,并且必须与要共享同一会话的所有应用程序相同。

谢谢。

更新:这是我在同一主题上回答的上一篇文章使用ASP.NET会话状态服务跨应用程序共享会话

正如已经指出的那样,会话数据的范围是应用程序。 这是您在IIS中创建的应用程序。 因此,具有相同会话ID的两个应用程序将不会因应用程序范围而共享同一会话。

作为一种可能或可能不适合您的替代想法。 您可以创建一个根应用程序,并在两个子文件夹中包含D:\ App1和D:\ App2的代码。

 d:\Root web.config \App1 default.aspx ... \App2 default.aspx ... 

然后在IIS中创建一个指向d:\ Root的应用程序。

您还可以在IIS中创建应用程序,然后在应用程序下创建两个虚拟目录,一个指向D:\ App1,另一个指向D:\ App2,然后他们也可以在应用程序级别共享一个web.config 。 至关重要的是,两个虚拟目录只是虚拟目录而不是作为应用程序创建。

所以硬盘布局可能看起来像这样

 D:\Root web.config D:\App1 default.aspx ... D:\App2 default.aspx ... 

创建指向D:\ Root的根应用程序,然后在应用程序下创建指向D:\ App1的两个虚拟目录App1和指向D:\ App2的App2。

两种情况下的效果是您实际上将一个应用程序拆分为两个部分,两个部分都在同一个Session范围内,因此两者的代码可以共享相同的会话数据。

您还必须确保两个Web服务器上的应用程序的应用程序路径必须相同。 这里有一篇旧文章可能有所帮助

http://support.microsoft.com/default.aspx?scid=kb;EN-US;q325056

我们目前遇到类似的问题,除了我们使用IIS 7.5并且我们隐藏了应用程序路径(不再使用元数据库)。 有谁知道使用IIS 7.5进行故障排除的方法?