【问题标题】:ASP.NET sessions timing out earlyASP.NET 会话提前超时
【发布时间】:2025-12-08 16:15:02
【问题描述】:

我已经实现了一个从a control by Kenneth Scott 派生的自定义 ASP.NET 会话超时控件。它由 .NET 4 中的 IIS7 托管。

长话短说,它是一个服务器控件(实现 System.Web.UI.WebControls.WebControl),我包含在我的站点母版页中。该控件是不可见的,并在呈现页面时启动计时器。 X 分钟过去后,会显示一个 DIV,告诉用户他们的会话超时,并为他们提供一个按钮,让他们在想要保持登录状态时单击。

单击该按钮只会触发标准回发到服务器。除了重置会话的滑动到期之外,它不会在服务器上执行任何有用的工作。

超时控制配置为在会话到期前一分钟启动。当它达到 0 时,会话也应该到期,我将用户重定向到登录页面并通知他们由于不活动而超时。

它在大多数情况下都很好用,但有时“不起作用”。该按钮对用户似乎仍然有效,但在尝试单击站点上的任何其他控件后,他们立即被转储到登录页面(在 web.config 中定义的标准 ASP.NET 行为)。

我向 click 事件处理程序添加了一些日志记录语句,发现它没有触发。我的假设是客户端正在向服务器发送请求,但由于会话已过期,我的事件处理程序永远不会触发。

我确信我的应用程序池没有被回收(它被配置为每天回收一次,并且没有进程或粘手的管理员正在编辑应用程序目录中的文件)。此故障是间歇性发生的。我们正在使用表单身份验证。

我在 web.config 中的 system.web 部分:

<sessionState mode="InProc" timeout="20" />
<authentication mode="Forms">
  <forms path="/" loginUrl="Pages/LoginPage.aspx" protection="All" timeout="20" slidingExpiration="true" />
</authentication>

我目前的解决方法是将会话和表单超时增加到 30 分钟,并为超时引入新的配置设置,该设置仍然会在 20 分钟后将用户注销。额外的 10 分钟提供了足够的填充,使我的控件按预期工作。

我不喜欢这个解决方案,因为它充其量只是一种解决方法。我觉得我没有充分理解 ASP.NET 会话超时机制(尽管已经阅读并重新阅读了 MSDN 文档)。谁能解释我看到的行为,或者指出我所做的任何错误假设?

【问题讨论】:

    标签: asp.net


    【解决方案1】:

    您可以尝试记录任何应用程序的结束和结束的原因,以排除它与此有关。我总是为此使用这个脚本(只需将它放在 global.asax 中):

    protected void Application_End()
      {
         Type httpRuntimeType = typeof (HttpRuntime);
    
         HttpRuntime runtime =
            (HttpRuntime)
            httpRuntimeType.InvokeMember("_theRuntime", BindingFlags.NonPublic
                                                        | BindingFlags.Static |
                                                        BindingFlags.GetField,
                                         null, null,
                                         null);
    
         if (runtime == null)
            return;
    
         string shutDownMessage =
            (string) runtime.GetType().InvokeMember("_shutDownMessage",
                                                    BindingFlags.NonPublic
                                                    | BindingFlags.Instance
                                                    | BindingFlags.GetField,
                                                    null,
                                                    runtime,
                                                    null);
    
         string shutDownStack =
            (string) runtime.GetType().InvokeMember("_shutDownStack",
                                                    BindingFlags.NonPublic
                                                    | BindingFlags.Instance
                                                    | BindingFlags.GetField,
                                                    null,
                                                    runtime,
                                                    null);
    
         EventLog log = new EventLog();
         log.Source = ".NET Runtime";
         log.WriteEntry(
            String.Format(
               "\r\n\r\n_shutDownMessage={0}\r\n\r\n_shutDownStack={1}",
               shutDownMessage,
               shutDownStack),
            EventLogEntryType.Information);
      }
    

    【讨论】: