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

Dav*_*Dev 11 c# asp.net asp.net-mvc session stateserver

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

设置:

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

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

<system.web>
<sessionState mode="StateServer" 
              cookieless="false" 
              timeout="20" 
              stateConnectionString="tcpip=127.0.0.1:42424" />
              //stateConnectionString="tcpip=192.168.1.52:42424" /> // also doesn't work
<machineKey 
  validationKey="8B9F68D0CC730F6F046D0173021C34B1A0D9A01C21D8E4D4A7A1DFF38332DEE8CBBAFEA503C18776614EE9D4F7EEA7E5D2D5571630547D822485A27B1EF53AC1"
  decryptionKey="60009563EFCFC594FD1BC46684943AA398EE70412A624B2EB488BBB071F15ECF"
  validation="SHA1" decryption="AES" />
Run Code Online (Sandbox Code Playgroud)

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

考试:

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

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;
Run Code Online (Sandbox Code Playgroud)

在视图中有这个:

<p>
    Mode: <%= ViewData["mode"].ToString() %>
</p>
<p>
    Time: <%= ViewData["timestamp"].ToString() %>
</p>
<p>
    real time: <%= ViewData["realtime"].ToString() %>
</p>
Run Code Online (Sandbox Code Playgroud)

结果:

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

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

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

Dar*_*rov 10

默认情况下,不能在不同应用程序之间共享会话.从我可以看到你有两个不同的应用程序App1,App2它们运行在单独的虚拟目录中,甚至可能分开的应用程序池,所以不要期望在它们之间共享会话.

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


小智 6

实际上,您可以使用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
Run Code Online (Sandbox Code Playgroud)

然后将web.config修改为: -

<sessionState mode="SQLServer" sqlConnectionString="Data Source=.;Integrated Security=True;Application Name=TEST" cookieless="false" timeout="20"></sessionState>
   <httpRuntime targetFramework="4.5"/>
Run Code Online (Sandbox Code Playgroud)

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

谢谢.