2012-11-19 10 views
5

Ho implementato il codice per leggere le sessioni attive utilizzando il riferimento Reading All Users Session e Get a list of all active sessions in ASP.NET.Eccezione di riferimento NULL durante la lettura delle sessioni utente (Reflection)

Private List<String> getOnlineUsers() 
{ 
    List<String> activeSessions = new List<String>(); 
    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; 
} 

Funziona correttamente nel sistema locale (in Windows XP e Windows 7). Mentre ho ospitato l'applicazione nel server Windows 2003 (IIS versione 6), dà un errore riferimento a un oggetto NULL nella linea

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

E 'questo tutto ciò che riguarda il problema di autorizzazione o impostazioni del livello di fiducia relativi a IIS? Per favore, sappia che qualcuno ha riscontrato un problema simile. Qualsiasi aiuto è altamente apprezzabile.

+1

quale versione di .NET è installata nei 3 posti? e quale versione stai prendendo di mira? –

+0

Framework 3.5 è presente nel server. – TechDo

+0

3.5? o 3.5 SP1? –

risposta

0

Sembra una versione (o aggiornamento) diversa di .NET in esecuzione nel 2003 rispetto a XP/Win7, anche se potrebbe anche essere solo una differenza specifica della piattaforma. Se fossero permessi/fiducia, avresti visto un'eccezione. Invece, sembra più probabile che semplicemente: _cachesnon esiste su qualunque versione sia presente sulla macchina del 2003. Se si utilizza la reflection per accedere stato privato: si dovrebbe aspettare interamente esplodere tra le versioni/aggiornamenti/piattaforme/a-capriccio/ecc

Per indagare:

  • verifica se obj è null
  • verificare se obj.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance) è null

(una di quelle cose che potrebbero causare questa eccezione sulla linea si citi)

+0

Okay ... Potrebbe essere il caso, immagino. Perché lo stesso codice funziona in uno dei client sever (MS server 2003). – TechDo

+0

Hosting come directory virtuale/sito Web: questo problema? – TechDo

+0

@techdo l'unico modo per rispondere a quest'ultimo sarebbe confrontare ... probabilmente sei nella posizione migliore per provarlo. –

0

Esattamente per il tuo business case c'è la variabile dello stato dell'applicazione in asp.net. È simile allo stato della sessione, ma è visibile per tutte le richieste degli utenti.

1

So che questo è un thread vecchio, ma questo potrebbe salvare qualcuno un po 'di tempo. Un'altra cosa da controllare è che ogg è di tipo System.Web.Caching.CacheMultiple. Ho avuto lo stesso problema ed era un problema specifico della piattaforma, come suggerito da Marc Gravell. Si è scoperto che sul server Windows 2003, obj era di tipo System.Web.Caching.CacheSingle e c'era un'eccezione di riferimento null durante il tentativo di ottenere il valore per "_caches".

Se questo è il caso, è ancora possibile ottenere un elenco di sessioni attive con (Hashtable)obj.GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);

1

provare a utilizzare questo, se _cachesRefs _caches è nullo. La funzione seguente restituirà tutte le raccolte di sessioni utente per tutte le versioni multiple di Windows e incluso Windows Server.

Funziona.

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; 

}

+1

i voids saranno var in questo esempio nei foreachs (void -> var – dewelloper

3

ho provato la soluzione di Paully, che non compilare in alcuni punti e portare a errori di runtime in altri. Ad ogni modo, ispirato al suo suggerimento (grazie mille! Il mio voto va per quello), sono arrivato al mio, che mi compila e mi fa ottenere i dati attesi.

Inoltre, sto restituendo un oggetto IEnumerable e sto utilizzando "yield return", che lo rende più performante per le grandi liste (tipo di caricamento lento dei dati).Ecco qui:

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; 
      } 
     } 
    } 
} 
+0

Awesome! Sì, l'ho digitato a mano e probabilmente ha avuto errori di battitura. Buona fortuna! – Paully