2012-11-19 9 views
5

Reading All Users SessionGet a list of all active sessions in ASP.NET 참조를 사용하여 활성 세션을 읽는 코드를 구현했습니다.사용자 세션을 읽는 동안 NULL 참조 예외가 발생했습니다. (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; 
} 

로컬 시스템 (Windows XP 및 Windows 7)에서는 정상적으로 작동합니다. 나는 Windows 서버 2003 (IIS 버전 6)에서 응용 프로그램을 호스팅하는 반면, IIS 관련 권한 문제 나 신뢰 수준의 설정과 관련이 아무것도 줄

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

에 NULL 개체 참조 오류가되어 준다? 누구든지 이러한 문제를 발견하게하십시오. 어떤 도움이라도 대단히 중요합니다.

+1

.NET의 어떤 버전이 3 곳에 설치되어 있습니까? 어떤 버전을 타겟팅하고 있습니까? –

+0

프레임 워크 3.5가 서버에 있습니다. – TechDo

+0

3.5? 3.5 SP1? –

답변

0

.NET의 다른 버전 (또는 업데이트)이 XP/Win7보다 2003 년에 실행되고있는 것 같지만 플랫폼에 따라 다를 수 있습니다. 권한/신뢰 인 경우 예외가 발생했을 것입니다. 대신, 간단하게 : _caches이 존재하지 않습니다.은 2003 시스템에있는 버전에 상관없이 존재합니다. 당신이 반사를 사용하는 경우 개인 상태에 액세스 : 당신이

조사에 등 /에 - 변덕/버전/업데이트/플랫폼 사이에 폭발 할 것으로 예상 전적으로해야합니다입니다

  • 체크 obj 여부를 null
  • obj.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance)null

여부를 확인

(그런 것들 중 하나는 당신이 인용 라인에이 예외가 발생할 수 있습니다)
+0

오케이 ... 아마도 그런 경우일지도 모릅니다. 동일한 코드가 클라이언트 sever (MS server 2003) 중 하나에서 작동하기 때문입니다. – TechDo

+0

가상 디렉터리/웹 사이트로 호스팅 -이 문제가 있습니까? – TechDo

+0

@techdo 유일한 방법은 그 마지막에 비교할 것입니다 ... 당신은 아마 그것을 시도하는 것이 가장 좋습니다 –

0

정확히 비즈니스 케이스의 경우 asp.net에 응용 프로그램 상태 변수가 있습니다. 이는 세션 상태와 유사하지만 모든 사용자 요청에 대해 볼 수 있습니다.

1

나는 이것이 오래된 스레드라는 것을 알고 있지만, 누군가에게 시간을 절약 할 수 있습니다. 검사 할 또 다른 사항은 obj가 System.Web.Caching.CacheMultiple 유형인지 확인하는 것입니다. 나는이 같은 문제가 있었고 Marc Gravell이 제안한 것처럼 플랫폼에 특정한 문제였습니다. Windows 2003 서버에서 obj는 System.Web.Caching.CacheSingle 유형이고 "_caches"값을 가져 오려고 할 때 null 참조 예외가 있음이 밝혀졌습니다.

이런 경우, 당신은 여전히 ​​_caches가 NULL 인 경우 (Hashtable)obj.GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);

1

시도는, _cachesRefs을이를 사용하여 활성 세션의 목록을 얻을 수 있습니다. 아래 함수는 Windows의 여러 버전과 Windows Server를 포함한 모든 사용자 세션 컬렉션을 반환합니다.

작동합니다.

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

voids는이 예에서 foreachs에서 변합니다 (void -> var – dewelloper

3

나는 몇 가지 포인트에서 컴파일하고 다른 사람의 오류를 런타임으로 이어질하지 않았다 Paully의 솔루션을 시도했습니다. 어쨌든, 그의 제안에 영감을 받았습니다 (제게 많은 표를 던졌습니다!). 나는 내 자신에게 와서 예상 한 데이터를 컴파일하고 얻습니다.

또한 IEnumerable을 반환하고 "수익률 반환"을 사용하여 큰 목록 (일종의 게으른 데이터로드)에 대해 더 많은 성과를냅니다.여기에 간다 :

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

) 그래, 손으로 직접 타이핑 했어. 아마도 오타가 있었을 것입니다. 행운을 빌어 요! – Paully

관련 문제