读取用户会话时出现NULL引用exception(reflection)

我已经使用引用阅读所有用户会话实现了用于读取活动会话的代码,并获取了ASP.NET中所有活动会话的列表 。

Private List getOnlineUsers() { List activeSessions = new List(); object obj = typeof(HttpRuntime).GetProperty("CacheInternal", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null, null); object[] obj2 = (object[])obj.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj); for (int i = 0; i < obj2.Length; i++) { Hashtable c2 = (Hashtable)obj2[i].GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj2[i]); foreach (DictionaryEntry entry in c2) { object o1 = entry.Value.GetType().GetProperty("Value", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(entry.Value, null); if (o1.GetType().ToString() == "System.Web.SessionState.InProcSessionState") { SessionStateItemCollection sess = (SessionStateItemCollection)o1.GetType().GetField("_sessionItems", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(o1); if (sess != null) { if (sess["loggedInUserId"] != null) { activeSessions.Add(sess["loggedInUserId"].ToString()); } } } } } return activeSessions; } 

它在本地系统中运行良好(在Windows XP和Windows 7中)。 当我在Windows Server 2003(IIS版本6)中托管应用程序时,它在行中提供了NULL对象引用错误

 object[] obj2 = (object[])obj.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj); 

这与IIS相关的权限问题或信任级别设置有关吗? 请让任何人遇到这样的问题。 任何帮助都非常值得赞赏。

我尝试过Paully的解决方案,它在某些方面没有编译,导致其他人的运行时错误。 无论如何,灵感来自他的建议(非常感谢!我的投票就是这样),我来到了我自己,它编译并获得预期的数据。

此外,我正在返回一个IEnumerable,我正在使用“yield return”,这使得它对大型列表(延迟加载数据)更具性能。 它来了:

 public static System.Collections.Generic.IEnumerable GetAllUserSessions() { List hTables = new List(); object obj = typeof(HttpRuntime).GetProperty("CacheInternal", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null, null); dynamic fieldInfo = obj.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance); //If server uses "_caches" to store session info if (fieldInfo != null) { object[] _caches = (object[])fieldInfo.GetValue(obj); for (int i = 0; i <= _caches.Length - 1; i++) { Hashtable hTable = (Hashtable)_caches[i].GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(_caches[i]); hTables.Add(hTable); } } //If server uses "_cachesRefs" to store session info else { fieldInfo = obj.GetType().GetField("_cachesRefs", BindingFlags.NonPublic | BindingFlags.Instance); object[] cacheRefs = fieldInfo.GetValue(obj); for (int i = 0; i <= cacheRefs.Length - 1; i++) { var target = cacheRefs[i].GetType().GetProperty("Target").GetValue(cacheRefs[i], null); Hashtable hTable = (Hashtable)target.GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(target); hTables.Add(hTable); } } foreach (Hashtable hTable in hTables) { foreach (DictionaryEntry entry in hTable) { object o1 = entry.Value.GetType().GetProperty("Value", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(entry.Value, null); if (o1.GetType().ToString() == "System.Web.SessionState.InProcSessionState") { SessionStateItemCollection sess = (SessionStateItemCollection)o1.GetType().GetField("_sessionItems", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(o1); if (sess != null) yield return sess; } } } } 

我知道这是一个旧线程,但这可能会节省一些时间。 要检查的另一件事是obj是System.Web.Caching.CacheMultiple类型。 我有同样的问题,这是一个特定于平台的问题,正如Marc Gravell建议的那样。 事实certificate,在Windows 2003服务器上,obj是类型System.Web.Caching.CacheSingle,并且在尝试获取“_caches”的值时存在空引用exception。

如果是这种情况,您仍然可以获得一个活动会话列表(Hashtable)obj.GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);

如果_caches为NULL,请尝试使用_cachesRefs。 下面的函数将返回所有多个Windows版本的所有用户会话集合,包括Windows Server。

有用。

 public List GetAllUserSessions() { List hTables = new List(); PropertyInfo propInfo = typeof(HttpRuntime).GetProperty("CacheInternal", BindingFlags.NonPublic | BindingFlags.Static); object CacheInternal = propInfo.GetValue(null, null); dynamic fieldInfo = CacheInternal.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance); if (fieldInfo != null) { object[] _caches = (object[])fieldInfo.GetValue(CacheInternal); for (int i = 0; i <= _caches.Length - 1; i++) { Hashtable hTable = (Hashtable)_caches(i).GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(_caches(i)); hTables.Add(hTable); } } else { fieldInfo = CacheInternal.GetType().GetField("_cachesRefs", BindingFlags.NonPublic | BindingFlags.Instance); dynamic cacheRefs = fieldInfo.GetValue(CacheInternal); foreach (void cacheRef_loopVariable in cacheRefs) { cacheRef = cacheRef_loopVariable; dynamic target = cacheRef.Target; fieldInfo = target.GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance); Hashtable hTable = fieldInfo.GetValue(target); hTables.Add(hTable); } } List sessionlist = new List(); foreach (void hTable_loopVariable in hTables) { hTable = hTable_loopVariable; foreach (DictionaryEntry entry in hTable) { object value = entry.Value.GetType().GetProperty("Value", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(entry.Value, null); if (value.GetType().ToString() == "System.Web.SessionState.InProcSessionState") { SessionStateItemCollection sCollection = (SessionStateItemCollection)value.GetType().GetField("_sessionItems", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(value); if (sCollection != null) sessionlist.Add(sCollection); } } } return sessionlist; 

}

听起来,2003年运行的.NET版本(或更新版本)与XP / Win7版本不同,尽管它也可能只是特定于平台的差异。 如果是权限/信任,您会看到exception。 相反,它似乎更简单:在2003机器上的任何版本上都不存在 _caches 。 如果你使用reflection访问私有状态:你应该完全期望它在版本/更新/平台/ at-whim /等之间爆炸。

去弄清楚:

  • 检查obj是否为null
  • 检查obj.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance)是否为null

(这些事情中的任何一个都可能导致你引用的这个例外)

正是因为您的业务案例,asp.net中有Application状态变量。 它类似于会话状态,但对所有用户请求都可见。