I have implemented the code for reading the active sessions using the reference Reading All Users Session and Get a list of all active sessions in ASP.NET.
P
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;
}
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.
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:
obj
is null
obj.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance)
is null
(either of those things could cause this exception on the line you cite)
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;
}
}
}
}
As of Feb. 2010, testing on IIS 10.0 (Windows 10), the above solutions didn't quite work, so I hacked together the following which worked for me. It builds on awerdan's answer and incorporates Diogo Damiani's.
// attempt to get Asp.Net internal cache
// adapted from https://stackoverflow.com/a/46554310/1086134
private static object getAspNetInternalCacheObj ()
{
object aspNetCacheInternal = null;
PropertyInfo cacheInternalPropInfo = typeof(HttpRuntime).GetProperty("CacheInternal", BindingFlags.NonPublic | BindingFlags.Static);
if (cacheInternalPropInfo != null)
{
aspNetCacheInternal = cacheInternalPropInfo.GetValue(null, null);
return aspNetCacheInternal;
}
// At some point, after some .NET Framework's security update, that internal member disappeared.
// https://stackoverflow.com/a/45045160
//
// We need to look for internal cache otherwise.
//
var cacheInternalFieldInfo = HttpRuntime.Cache.GetType().GetField("_internalCache", BindingFlags.NonPublic | BindingFlags.Static);
if (cacheInternalFieldInfo == null)
return null;
var httpRuntimeInternalCache = cacheInternalFieldInfo.GetValue(HttpRuntime.Cache);
var httpRuntimeInternalCacheField = httpRuntimeInternalCache.GetType().GetField("_cacheInternal", BindingFlags.NonPublic | BindingFlags.Instance);
if (httpRuntimeInternalCacheField == null)
return null;
aspNetCacheInternal = httpRuntimeInternalCacheField.GetValue(httpRuntimeInternalCache);
return aspNetCacheInternal;
}
// adapted from https://stackoverflow.com/a/39422431/1086134
private static IEnumerable<System.Web.SessionState.SessionStateItemCollection> getAllUserSessions()
{
List<Hashtable> hTables = new List<Hashtable>();
object obj = getAspNetInternalCacheObj();
if (obj == null)
yield break;
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")
{
System.Web.SessionState.SessionStateItemCollection sess = (System.Web.SessionState.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);