最近,在为工作的ASP.NET项目编写一些代码时.我们需要一个跟踪工具来获取我们将跟踪它们的用户活动(页面命中数等)的基本指标Session
,然后通过Session_End
输入将数据保存到DB Global.asax
.
我开始乱砍,初始代码工作正常,在每个页面加载时更新数据库.我希望在每个请求中删除此数据库命中,然后只依赖于Session_End
存储所有数据.
所有跟踪代码都封装在Tracker
类中,包括基本上包装Session变量的属性.
问题 是,当我Tracker.Log()
在Session_End
方法中执行时,HttpContext.Current.Session
Tracker代码中的a失败了NullReferenceException
.现在,这是有意义的,因为HttpContext
始终与当前请求相关,当然Session_End
,没有请求.
我知道Global.asax
有一个Session
属性返回一个HttpSessionState
实际上似乎工作正常(我最终注入到跟踪器)..
不过我很好奇,到底如何才能得到相同的参考HttpSessionState
使用对象Global.asax
从外面的Global.asax
?
先谢谢你们,我很感激你的意见.:)
更好地回答原始问题:
每个页面请求都会旋转一个新Session
对象,然后将其从会话存储中膨胀.为此,它使用客户端提供的cookie或特殊路径构造(用于无cookie会话).使用此会话标识符,它会查询会话存储并反序列化(这是为什么所有提供程序,但InProc需要可序列化)新会话对象.
对于InProc提供者,只需将您存储在HttpCache
会话标识符键入的引用交给您.这就是InProc提供程序在AppDomain
回收时丢弃会话状态的原因(以及多个Web服务器无法共享InProc会话状态的原因).
这个新创建和膨胀的对象卡在Context.Items
集合中,以便在请求期间可用.
Session
然后,通过序列化(或InProc的情况,HttpCache
更新条目),在对会话存储的请求结束时将对对象所做的任何更改保留.
由于在Session_End
没有当前请求的情况下发生火灾,因此该Session
对象在ex-nilo上旋转,没有可用信息.如果使用InProc会话状态,则会HttpCache
在您的Session_End
事件中触发回调事件,因此会话条目可用,但仍然是上次存储的内容的副本HttpContext.Cache
.该值HttpApplication.Session
通过内部方法(称为ProcessSpecialRequest
)存储在属性中,然后可用.在所有其他情况下,它内部来自HttpContext.Current.Session
价值.
由于Session_End总是针对空上下文触发,因此您应该始终在该事件中使用this.Session并将HttpSessionState对象传递给您的跟踪代码.在所有其他上下文中,从fetch获取HttpContext.Current.Session
然后传入跟踪代码是完全正常的.不要,但是,让跟踪代码可达的会话环境.
不要使用Session_End
,除非你知道会话存储使用的是支持Session_End
,它确实如果它返回true
的SetItemExpireCallback
.唯一的商店就是InProcSessionState
商店.可以编写一个会话存储,但是Session_End
如果有多个服务器,那么处理该会话存储的问题是多么模糊.
Global.asax实现了HttpApplication - 当你调用它时,你正在谈论它来自其内部.
HttpApplication的MSDN文档详细介绍了如何在HttpHandler中获取它,然后访问它上面的各种属性.
然而
您的应用程序可以创建多个HttpApplication实例来处理并行请求,这些实例可以重复使用,所以只是以某种方式提取它并不能保证您拥有正确的实例.
我也会添加一个注意事项 - 如果你的应用程序崩溃了,那么就没有保证会调用session_end,你将丢失所有会话中的所有数据,显然不是一件好事.
我同意登录每个页面可能不是一个好主意,但也许是一个中途发生异步日志记录的房子 - 你将详细信息发送到日志记录类,不时地记录你之后的详细信息 - 仍然不是100%如果应用程序崩溃,则可靠,但您不太可能丢失所有内容.