使用asp.net和状态服务器在两个网站之间共享会话

时间:2010-08-09 09:57:43

标签: c# asp.net iis state

我在IIS 7.5下有两个完全相同的网站托管在两台不同的机器上。 ASP.NET状态服务正在我的机器上运行,web.config在两个站点中都使用以下代码进行更新:

<sessionState mode="StateServer" stateConnectionString="tcpip=192.168.1.77:42424" cookieless="false" timeout="120"/>

允许远程连接在注册表中设置为1,以便第二个网站访问状态服务器。

两个网站都有相同的机器密钥:

<machineKey validationKey="7CB8DF6872FB6B35DECD3A8F55582350FEE1FAB9BE6B930216056C1B5BA69A4C5777B3125A42C4AECB4419D43EC12F168FD1BB887469798093C3CAA2427B2B89" decryptionKey="02FC52E4C71544868EE297826A613C53537DF8FDAF93FA2C64E9A5EF0BA467FB" validation="SHA1" decryption="AES" />

此外,两个站点在IIS中配置为具有相同的标识符。

我想要做的是这两个网站共享相同的会话数据,例如能够执行以下操作:

// At web site 1: 
Session["key"] = "value"

// At web site 2:
// Read session value from the other web site
string result = Session["key"]

问题是我无法完成这项测试,实在无法理解我做错了什么。

任何可能有帮助的想法?

4 个答案:

答案 0 :(得分:11)

我知道这个问题已于5年前得到解答,但今天我想我可以在其中提供更多信息。

首先,这不是在两个IIS应用程序之间共享会话数据的官方方式,也不是最流行的方式。 “看似官方”的方式是use SQL Server session

如果您因任何原因无法使用SQL服务器,那么我们可以稍微调整一下IIS应用程序,以便我们可以使用进程外会话,即 StateServer 会话状态模式。

为了使其有效,有很多事情要做:

  1. 2个应用程序的会话cookie必须设置在同一个域名中。 E.g。
  2. <httpCookies domain=".your.site"/>
    
    1. 必须匹配机器密钥。您可以执行标准Web.config field encryption以使其更安全,但这是可选的。
    2. <machineKey validationKey="[your_key]" 
          decryptionKey="[your_decryption_key]" validation="SHA1" />
      
      1. 会话状态模式设置为状态服务器
      2. 将(1),(2),(3)放在一起:

        <system.web>
            <httpCookies domain=".your.site"/>
            <machineKey validationKey="your_key" decryptionKey="your_decryption_key" validation="SHA1" />
            <sessionState mode="StateServer" timeout="60" />
            ...
        
        1. 必须匹配应用程序名称。如果不是,则只能共享会话ID,而不能共享会话数据。问题是您无法在Web.config中配置应用程序名称。然而,我们可以创建自己的配置,然后通过反射注入它。只需将以下代码放在Global.asax.cs中:

          public override void Init()
          {
              base.Init();
              try
              {
                  // Get the app name from config file...
                  string appName = ConfigurationManager.AppSettings["ApplicationName"];
                  if (!string.IsNullOrEmpty(appName))
                  {
                      foreach (string moduleName in this.Modules)
                      {
                          IHttpModule module = this.Modules[moduleName];
                          SessionStateModule ssm = module as SessionStateModule;
                          if (ssm != null)
                          {
                              FieldInfo storeInfo = typeof(SessionStateModule).GetField("_store", BindingFlags.Instance | BindingFlags.NonPublic);
                              SessionStateStoreProviderBase store = (SessionStateStoreProviderBase)storeInfo.GetValue(ssm);
                              if (store == null) //In IIS7 Integrated mode, module.Init() is called later
                              {
                                  FieldInfo runtimeInfo = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.Static | BindingFlags.NonPublic);
                                  HttpRuntime theRuntime = (HttpRuntime)runtimeInfo.GetValue(null);
                                  FieldInfo appNameInfo = typeof(HttpRuntime).GetField("_appDomainAppId", BindingFlags.Instance | BindingFlags.NonPublic);
                                  appNameInfo.SetValue(theRuntime, appName);
                              }
                              else
                              {
                                  Type storeType = store.GetType();
                                  if (storeType.Name.Equals("OutOfProcSessionStateStore"))
                                  {
                                      FieldInfo uribaseInfo = storeType.GetField("s_uribase", BindingFlags.Static | BindingFlags.NonPublic);
                                      uribaseInfo.SetValue(storeType, appName);
                                  }
                              }
                          }
                      }
                  }
          
              }
              catch (Exception ex)
              {
                  log.Error(ex.Message, ex);
              }
          }
          

          积分转到pfemianiLi Chen,以及我不记得是谁将其汇总到代码项目的评论中。请注意,pfemiani的答案对我不起作用,但将其与李晨的帖子结合起来了。

        2. 确保ASP .NET state service正在运行。这是会议数据现在保存的地方。

答案 1 :(得分:4)

您需要一种方法来说服您的浏览器发送相同的ASP.NET会话cookie,无论它访问哪个站点。

如果请求中不存在cookie,则将使用该密钥创建新会话。

我认为你可以通过一些偷偷摸摸的DNS配置让浏览器保留密钥 - 如果你指定http://website1.mydomain.com/http://website2.domain.com/作为你网站的地址,那么设置ASP的域名。 NET会话cookie到“domain.com”,然后您的浏览器将其发送到两个站点,并且会话应该共享。

您也可以在ASP.NET中使用cookieless模式,并从生成的URL中获取会话ID。

答案 2 :(得分:0)

在两个asp.net Web应用程序之间共享会话

请参阅以下网址

http://www.freshcodehub.com/Article/48/sharing-session-between-two-aspnet-web-applications

答案 3 :(得分:0)

我的问题是我的两个应用程序使用的是Owin库的不同主要版本。一旦我确保两个应用程序之间的所有Owin库共享相同的版本,就可以按照HoàngLong发布的答案使它起作用。