【问题标题】:ASP.NET randomly losing session valuesASP.NET 随机丢失会话值
【发布时间】:2011-08-05 15:28:39
【问题描述】:

我一直在寻找答案,因为它继续困扰着我。我们将用户登录信息和有关用户当前活动的其他数据存储在会话状态 (InProc) 中。每隔一段时间,我就会在尝试使用其中一个会话变量时遇到空引用异常。它发生在随机页面上,带有随机 Session 变量。我已经修改了 web.config httpRuntime 和 compliation 标签以防止 appPool 重启:

<httpRuntime requestValidationMode="2.0" waitChangeNotification="86400" maxWaitChangeNotification="86400" />
<compilation debug="False" strict="false" explicit="true" targetFramework="4.0" numRecompilesBeforeAppRestart="1000" />

我已将 IIS 设置为在凌晨 3 点重新启动应用程序池,以确保当人们忙于使用服务器时它不会重新启动。我正在事件日志中记录应用程序池重新启动,以确保我知道它何时发生。

Dim runtime As HttpRuntime = GetType(System.Web.HttpRuntime).InvokeMember("_theRuntime", BindingFlags.NonPublic Or BindingFlags.Static Or BindingFlags.GetField, Nothing, Nothing, Nothing)
Dim shutDownMessage As String = runtime.GetType().InvokeMember("_shutDownMessage", BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.GetField, Nothing, runtime, Nothing)

Dim shutDownStack As String = runtime.GetType().InvokeMember("_shutDownStack", BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.GetField, Nothing, runtime, Nothing)
Dim evtSource As String = "ASP.NET"
Dim log As New EventLog
log.Source = evtSource
log.WriteEntry(String.Format("_shutDownMessage={0}{2}_shutDownStack={1}", shutDownMessage, shutDownStack, vbCrLf & vbCrLf), EventLogEntryType.Warning)

当应用程序池重新启动时,我会收到事件日志条目。 发生这些错误时,应用程序池不会重新启动。

当特定会话变量丢失时,同一用户的大多数其他会话变量仍然存在。此外,通常还有 10 到 20 名登录该网站的用户在发生这种情况时不受影响。
收到错误的用户将备份,再次浏览相同的页面,它会正常工作。

我在运行带有 .NET 3.5 32 位和 4GB 内存的 IIS6 的 Windows Server 2003(32 位)上遇到了这个问题。大约一年前,作为我们服务器升级的一部分,我们得到了一个新的网络服务器 - Windows Server 2008(64 位) ) 运行具有 16GB 内存的 IIS 7。我将网站升级到 .NET 4.0 64 位。在新机器上仍然存在同样的问题(通常每天 1-3 次 - 一天中的随机时间)。

由于它的随机性,我无法在调试中实现它,但我相信它也会在我们的开发环境中随机发生。开发服务器的规格与生产服务器几乎相同。
两种环境都是隔离的,并作为单个 Web 服务器运行,而不是 Web 场的一部分。

我在想我可能会尝试实现一个状态服务器来摆脱 InProc 模式,但这只是在黑暗中的又一次尝试..
除了尝试状态服务器之外,我还能做些什么来确定这种情况何时发生或防止它发生?

【问题讨论】:

  • 尝试在StackOverflow上搜索,有很多相同的问题有很多建议
  • 您是否在负载均衡器后面运行两个 Web 服务器? (并且您确定您已经仔细检查了代码的设置位置以确保它们没有被覆盖)?
  • 我一直在通过代码反复寻找我可能无意中覆盖它们的地方,但找不到我所在的任何地方。此外,它发生在不同会话变量的许多不同页面上 - 以及不同的用户/浏览器/平台。发生这种情况时,我找不到实例之间的任何关联
  • 可能值得仔细检查您没有任何空的 catch 块。如果您尝试向会话添加一个不可序列化的对象(或包含不可序列化的嵌套对象的对象),它将抛出。但是,如果您正在捕获并吃掉抛出的异常,您最终可能会遇到一种情况,即您认为您在会话中添加了一些东西,但它却悄悄地失败了。
  • @mikemanne - 这是个好主意,如果/当我实现状态服务器时,我肯定会检查 NonSerializable 对象,但由于它当前是 InProc,我可以将任何对象添加到 Session,不仅可序列化的对象。这是我还没有完成状态服务器的原因之一 - 有很多地方要经过并确保所有对象都是可序列化的..

标签: asp.net session


【解决方案1】:

如果您的网络应用程序部署在服务器场(多于一个服务器网络)上 正如您所说,您正在使用 InProc 会话,并且可能会发生用户被重定向到与存储该会话变量的服务器不同的服务器。 在这种情况下,您应该像您提到的那样进行一次进程外会话(会话状态服务器)

如果您选择状态服务器,请记住以下内容,以防止出现任何其他问题:

由于 Stateserver 将 ASP.NET 会话 ID 与 IIS 创建唯一密钥的应用程序路径,为其中之一发出的会话 通过其中一个访问时找不到这五个新网站 其他在加权中显然非常不幸的网络 循环负载平衡网络农场

http://www-jo.se/f.pfleger/session-lost

还可以查看此记录器以了解应用是否违反您的意愿回收:

http://weblogs.asp.net/scottgu/archive/2005/12/14/433194.aspx

http://blogs.msdn.com/b/tess/archive/2006/08/02/asp-net-case-study-lost-session-variables-and-appdomain-recycles.aspx

【讨论】:

  • 这也是我的第一个想法。但是,由于他说“当特定 Session 变量丢失时,同一用户的大多数其他 Session 变量仍然存在。”,我不太可能怀疑会话关联失败。
  • 这可能会发生。也许用户在服务器 1 上(假设创建了几个会话变量)然后如果请求由服务器 2 提供服务并且代码尝试访问该服务器上不存在的会话变量,它将得到一个 null参考
  • 对不起,我也应该指定的.. 只有 1 台服务器,而不是服务器场
  • 我以前看过 ScottGu 页面。我使用他的一些代码来处理应用程序池关闭日志记录——我已经用该代码更新了原始帖子。问题是,我认为这根本不会发生.. 在线上的其他所有人都保持活跃并且不会丢失任何会话值。加上它碰巧保持活动状态的用户(他们的用户信息在会话中)并且他们在会话中有其他不受影响的值。
  • 尝试使用“您如何确定导致 appdomain 重新启动的原因?”段落的最后一个链接中显示的运行状况监控事件
【解决方案2】:

对于任何感兴趣或处理类似问题的人,我想在此处跟进我的问题的原因。

大约 7 或 8 个月前,我为应用程序缓存和会话状态实现了 NCache 进程外状态服务器。不幸的是,将会话移出进程并没有对我在我的站点上选择报告期间丢失随机会话变量的问题产生任何影响。而且,由于我无法复制这个问题,所以直到最近另一个问题让我的头脑中的光熄灭时,我才投入更多精力来尝试解决它。​​

直截了当——我没有在我没有意识到的地方覆盖会话变量,但问题是用户打开了第二个(或第三个)选项卡来并排比较报告选择选项。我们有几个自定义报告,用户可以在其中选择多个选项来生成自定义报告(把它想象成一个向导控件,其中有几个步骤来创建自定义报告)。如果用户在第 3 步(共 5 步),然后打开一个新选项卡并再次开始执行报告选择过程,则新选择将覆盖旧选择 b/c 2 个选项卡共享同一会话。我通过打开多个选项卡并逐步完成选择过程来验证是这种情况。

我正在尝试区分多个报告运行,以便使用与其他报告选择不同的唯一会话密钥来存储一个报告的选择。事实证明这也很困难,但与我认为丢失会话数据的问题并没有真正的关系。

如果有人发现这篇文章并认为他们正在随机丢失会话数据并且无法复制它,请尝试调试您的网站并打开多个标签。同时浏览两个选项卡对我来说是个问题。

HTH

【讨论】:

  • 有类似的问题,问题很难复制......(其他用户没有,我认为浏览器不会导致这种情况,因为浏览器的工作是只发送 sesisonid)。但以上是合乎逻辑的原因,我们将探讨用户是否打开多个页面。
  • 通过使用更好的设计来避免这种多页问题。从会话变量中删除所有客户端状态并将它们放在查询字符串中......即。 ?reportname=summary&page=1&pagelength=20&reportparameter1=etc 我的观点是,当用户登录或返回 cookie 时,Session 仅对存储用户 ID 或哈希有用。
  • @Awerealis,是的,如果您只有几个参数,在查询字符串中传递参数确实是一种选择。不幸的是,我的页面上发生了很多事情,我已经在使用 scriptManager 历史状态,它使用哈希值加载 url: 由于大量历史状态参数,我不得不增加 httpRuntime maxURLLength b/c 260 不够长。更不用说会话中有很多我们不想/不需要向客户端公开的事实。
【解决方案3】:

您面临的会话问题可能由于多种原因而发生

  1. 会话过期:当您使用 Inproc 模式时,会话是 仅对 sessiontimeout 时间段有效。这是20分钟 默认。尝试在您的 system.web 部分中使用 sessionstate 标签 web .config 并将超时值设置为更大的值。

  2. 另一个问题可能是由于网络农场和网络花园。如果 您已经为您的网站配置了网络农场和网络花园。 Inproc 会话共享可能会导致问题。

  3. 进程重新启动:您网站的 w3p 进程正在获取 由于代码中的一些问题而重新启动。或内存泄漏。

【讨论】:

    【解决方案4】:

    我遇到了这个问题,因为我们的服务器设置为运行 https。如果我在简单的 http 下运行,则不会保留会话。但是,在 https 上运行时会保留会话。因此,我们设置了一个 URL 重写规则,如果应用程序通过 http 进入,则始终将其发送到 https。

    此外,如果您的 web.config 文件中有以下内容,除非您正在运行 https(请注意 https 末尾的 S),否则会话将无法在本地或服务器上运行:

    <httpCookies httpOnlyCookies="true" requireSSL="true"/>
    

    【讨论】:

      【解决方案5】:

      由于我花了一段时间才弄清楚这一点,我想我会在这里发布它以防它也对其他人有所帮助。

      我遇到了 IE 和 Chrome 也随机删除会话变量的情况。我搜索再搜索,每个人都说平常的话...检查域名,检查 IIS 设置是否有 cookie...等等。

      我的问题原来是权限问题。

      在我的 web.config 中,我有一个“公共”文件夹的权限条目,未经身份验证的公众可以访问该文件夹。

      <location path="public">
      <system.web>
        <authorization>
          <allow users="*" />
          <allow users="?" />
        </authorization>
      </system.web>
      

      问题是对不在公共端的 HttpHandler 的公共端 .js 调用。 为了重用代码,我将安全端和公共端都指向安全端的代码。我想作为副作用,它终止了会话,没有非常有意义的错误消息。

      我可以仅为该处理程序添加另一个条目,或者我可以公开该代码的安全副本(一种不太理想的方法)。

      【讨论】:

        【解决方案6】:

        还有一个条件是会话可能会失去其价值。

        您可以使用 Fiddler 工具来追踪这个问题。

        当您在解决方案中找不到某些元素(如源)时,可以找到大多数情况。在那一刻,服务器将尝试通过重新启动项目来重新加载那个毫无根据或丢失的对象。重新启动项目将导致重置所有会话对象。

        谢谢。

        【讨论】:

          猜你喜欢
          • 2012-05-15
          • 2017-02-04
          • 1970-01-01
          • 2012-02-19
          • 2017-09-20
          • 1970-01-01
          • 2010-10-20
          • 1970-01-01
          • 2021-03-03
          相关资源
          最近更新 更多