【问题标题】:"HttpContext.Current.Session" vs Global.asax "this.Session"“HttpContext.Current.Session”与 Global.asax “this.Session”
【发布时间】:2013-05-31 01:55:11
【问题描述】:

最近,在为工作中的 ASP.NET 项目编写一些代码时。我们需要一个跟踪工具来获取用户活动的基本指标(页面点击计数等),我们将在Session 中跟踪它们,然后通过Global.asax 中的Session_End 将数据保存到数据库。

我开始破解,初始代码运行良好,在每个页面加载时更新数据库。不过,我想删除每个请求中的这个数据库命中,只依靠Session_End 来存储所有数据。

所有跟踪代码都封装在Tracker 类中,包括本质上包装会话变量的属性。

问题是,当我在Session_End 方法中执行Tracker.Log() 时,Tracker 代码中的HttpContext.Current.SessionNullReferenceException 失败。现在,这是有道理的,因为 HttpContext 总是与 当前 请求相关,当然在 Session_End 中,没有请求。

我知道Global.asax 有一个Session 属性,它返回一个HttpSessionState,实际上似乎工作正常(我最终将它注入到跟踪器中)..

但我很好奇,我怎么能从Global.asax外部获得Global.asax使用的HttpSessionState对象的相同引用?

在此先感谢各位,感谢您的意见。 :)

【问题讨论】:

  • 另一个注意事项是 Session_End 也不能保证被调用。 SQL 会话和状态外会话设置就是这种情况。
  • 哪位好心人可以为这个问题的答案放一个代码sn-p让初学者理解。如何在“in Proc”模式下访问存储在应用程序中 current.session somnwhere 中的值,然后在 global.asax 文件中访问它。我可以简单地在session_end 中使用this.session 还是需要一些额外的代码?
  • 另外,如果有多个用户登录到该站点。那么this 会单独引用每个请求对吗?

标签: asp.net session session-state global-asax


【解决方案1】:

为了更好地回答原始问题:

背景

每个页面请求都会启动一个新的Session 对象,然后从您的会话存储中扩充它。为此,它使用客户端提供的 cookie 或特殊路径构造(用于无 cookie 会话)。使用此会话标识符,它会查询会话存储并反序列化(这就是除了 InProc 之外的所有提供程序都需要可序列化的原因)新会话对象。

对于 InProc 提供程序,只需将它存储在由会话标识符键入的 HttpCache 中的引用交给您。 这就是为什么 InProc 提供程序会在 AppDomain 被回收时丢弃会话状态(也是多个 Web 服务器无法共享 InProc 会话状态的原因

这个新创建和膨胀的对象卡在Context.Items 集合中,因此在请求期间它是可用的。

然后,您对 Session 对象所做的任何更改都会在对会话存储的请求结束时通过序列化(或者在 InProc 的情况下,HttpCache 条目被更新)进行持久化。

由于Session_End 在没有当前请求的情况下触发,Session 对象在没有可用信息的情况下自动旋转。如果使用 InProc 会话状态,HttpCache 的到期会触发一个回调事件到您的Session_End 事件中,因此会话条目可用,但仍然是上次存储在 HttpContext.Cache 中的内容的副本。该值通过内部方法(称为ProcessSpecialRequest)针对HttpApplication.Session 属性存储,然后可用。在所有其他情况下,它在内部来自 HttpContext.Current.Session 值。

你的答案

由于 Session_End 总是针对空 Context 触发,因此您应该始终在该事件中使用 this.Session 并将 HttpSessionState 对象传递给您的跟踪代码。在所有其他情况下,从HttpContext.Current.Session 获取然后传递给跟踪代码是完全可以的。但是,不要让跟踪代码到达会话上下文。

我的回答

不要使用Session_End,除非您知道您正在使用的会话存储支持Session_End,如果它从SetItemExpireCallback 返回true,它支持。唯一的开箱即用商店是InProcSessionState 商店。可以编写一个会话存储,但如果有多个服务器,谁将处理 Session_End 的问题有点模棱两可。

【讨论】:

    【解决方案2】:

    Global.asax 实现 HttpApplication - 当您在其中调用 this 时,您正在与它对话。

    HttpApplication 的 MSDN 文档详细介绍了如何在 HttpHandler 中获取它,然后访问它的各种属性。

    但是

    您的应用程序可以创建多个 HttpApplication 实例来处理并行请求,并且这些实例可以重复使用,因此仅以某种方式获取它并不能保证您拥有正确的实例。

    我还要注意一点 - 如果您的应用程序崩溃,则无法保证 session_end 会被调用,并且您将丢失所有会话中的所有数据,这显然不是一件好事。

    我同意在每个页面上记录可能不是一个好主意,但可能是发生一些异步记录的中途之家 - 您将详细信息发送到日志记录类,它不时记录您所追求的详细信息 - 仍然如果应用崩溃,则不是 100% 可靠,但您不太可能丢失所有内容。

    【讨论】:

    • 很好的答案,帮助我了解了一些事情。也完全同意最后一段。考虑在跟踪器上设置一个滑动过期时间,以便在会话超时之前记录信息并且没有 Session_End。再次感谢:)
    【解决方案3】:

    我想你已经回答了你自己的问题:通常 Global.asax 和 HttpContext.Current.Session 中的 Session 属性是相同的(如果有当前请求)。但是在会话超时的情况下,没有活动请求,因此您不能使用 HttpContext.Current。

    如果要从 Session_End 调用的方法中访问会话,则将其作为参数传递。创建一个重载版本的 Log() 方法,该方法将 HttpSessionState 作为参数,然后从 Session_End 事件处理程序调用 Tracker.Log(this.Session)。

    顺便说一句:您知道在任何情况下都不能依赖会话结束事件吗?只要您有正在进行的会话状态,它就会起作用。使用 SQL server 或 StateServer 管理会话状态时,不会触发会话结束事件。

    【讨论】:

    • 但我的问题是“如何获得对 Global.asax 使用的同一对象的引用”? :)
    【解决方案4】:

    仅当 Web.config 文件中的 sessionstate mode 设置为 InProc 时,才会引发 Session_End 事件。如果会话模式设置为StateServerSQLServer,则不会引发事件。

    使用Session["SessionItemKey"] 获取会话值。

    【讨论】:

      【解决方案5】:

      好的,我在跟踪会话活动时遇到了同样的问题。我没有使用 session_end 事件,而是为我的 sessiontracker 类实现了 IDisposable 接口和析构函数。我已修改 Dispose() 方法以将会话活动保存到数据库。当用户单击注销按钮时,我调用了方法 obj.Dispose()。如果用户错误地关闭了浏览器,那么 GC 将在清理对象时调用析构函数(不是立即,但肯定会在一段时间后调用此方法)。析构函数方法在内部执行相同的 Dispose() 方法以将会话活动保存到 DB 中。

      -山

      【讨论】:

        【解决方案6】:

        在 Session_Start 事件期间,您的 Global.asax 文件中提供了会话。也许等到这一点做的事情?

        【讨论】:

          【解决方案7】:

          请记住,Session_End 会在会话超时而无活动时运行。浏览器不会发起该事件(因为它处于非活动状态),因此您真正获得该事件的唯一时间是使用 InProc 提供程序时。在每个其他提供程序中,此事件将永远不会触发。

          道德?不要使用 Session_End。

          【讨论】:

          • 公平点,但问题显然是基于我们*正在使用 Session_End 的假设(无论是好的还是坏的选择)
          • 那么,以一种可能会令人惊讶地失败的方式告诉某人他们做错了,是一个糟糕的答案吗?请参阅“敲钉子:旧鞋还是玻璃瓶?” is.gd/gSb1
          • 为了记录,我完全同意你的帖子的主要观点,但我个人认为它并没有对问题本身的“答案”做出贡献。“不要使用”没有帮助恕我直言..“试试这个不要使用”可能更有用.. :)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-31
          • 1970-01-01
          • 2016-03-10
          • 2019-04-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多