代码之家  ›  专栏  ›  技术社区  ›  DaveDev

为什么我不能与StateServer共享两个web应用之间的会话状态?我错过了什么?

  •  11
  • DaveDev  · 技术社区  · 14 年前

    我很难让两个相同的ASP.NET MVC应用程序使用会话StateServer共享同一个会话。我尝试这样做的原因是,我们最终将在需要共享相同状态的3个web服务器上部署此应用程序。我们需要使用StateServer,因为我们正在尽量减少对非数据相关存储的db使用。

    设置:

    我已经将相同的代码库部署到 http://localhost/ http://localhost/ 附录2

    两者都有相同的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" />
    

    我曾经 this tool to generate these machine keys

    测试:

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

    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;
    

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

    结果是:

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

    有没有人能指出我做错了什么,或者我还需要做些什么才能让这件事成功?谢谢

    4 回复  |  直到 14 年前
        1
  •  11
  •   Darin Dimitrov    14 年前

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

    就像往常一样 workarounds 你可能会觉得有用。正如您所看到的,它使用了一种黑客(反射)来规避ASP.NET团队设计器不公开某些类和属性的决心,并使我们作为开发人员的生活变得困难。

        2
  •  6
  •   Calyfs0    11 年前

    尝试this:-

    我只是改变了程序。

    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修改为:-

    <sessionState mode="SQLServer" sqlConnectionString="Data Source=.;Integrated Security=True;Application Name=TEST" cookieless="false" timeout="20"></sessionState>
       <httpRuntime targetFramework="4.5"/>
    

    谢谢。

        3
  •  3
  •   Community kfsone    7 年前

    更新:这是我之前关于这个话题的一篇文章 Sharing sessions across applications using the ASP.NET Session State Service

    如前所述,会话数据的作用域是应用程序。这就是您在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
      ...
    

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

        4
  •  2
  •   Brian Jones    14 年前

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

    我们目前也遇到了类似的问题,只是我们使用的是iis7.5,应用程序路径对我们来说是隐藏的(不再使用元数据库)。有人知道用iis7.5解决这个问题的方法吗?

    推荐文章