NULL reference exception while reading user sessions (Reflection)

好久不见. 提交于 2019-12-05 09:17:23

I've tried Paully's solution, which didn't compile in some points and lead to runtime errors in others. Anyway, inspired on his suggestion (thanks a lot! My vote goes for that), I came to my own, which compiles and gets me the expected data.

Also, I'm returning a IEnumerable and I'm using "yield return", which makes it more performatic for big lists (kind of lazy loading of data). Here it goes:

public static System.Collections.Generic.IEnumerable<SessionStateItemCollection> GetAllUserSessions()
{
    List<Hashtable> hTables = new List<Hashtable>();
    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;
            }
        }
    }
}

I know this is an old thread, but this may save someone some time. Another thing to check is that obj is of type System.Web.Caching.CacheMultiple. I had this same problem and it was a platform-specific issue as Marc Gravell suggested. It turned out that on the Windows 2003 server, obj was type System.Web.Caching.CacheSingle and there was a null reference exception when trying to get the value for "_caches".

If that is the case, you can still get a list of active sessions with (Hashtable)obj.GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);

Try using this, _cachesRefs if _caches is NULL. The function below will return all user sessions collections for all multiple versions of Windows and including Windows Server.

It works.

public List<SessionStateItemCollection> GetAllUserSessions() {

List<Hashtable> hTables = new List<Hashtable>();

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<SessionStateItemCollection> sessionlist = new List<SessionStateItemCollection>();

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;

}

It sounds like a different version (or update) of .NET is running on 2003 than you have on XP / Win7, although it could also just be a platform-specific difference. If it was permissions / trust, you would have seen an exception. Instead, it seems more likely that simply: _caches does not exist on whatever version is on the 2003 machine. If you use reflection to access private state: you should entirely expect it to explode between versions / updates / platforms / at-whim / etc.

To investigate:

  • check whether obj is null
  • check whether obj.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance) is null

(either of those things could cause this exception on the line you cite)

Exactly for your business case there is Application state variable in asp.net. It is similar to session state, but visible for all users request.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!