programing

활성 ASP를 모두 나열합니다.NET 세션

bestprogram 2023. 10. 9. 23:28

활성 ASP를 모두 나열합니다.NET 세션

현재 ASP를 모두 나열(반복)하려면 어떻게 해야 합니까?NET 세션?

global.asax 이벤트 Session_Start 및 Session_End에서 세션에 대한 데이터를 수집할 수 있습니다(프로 내 설정에서만).

private static readonly List<string> _sessions = new List<string>();
private static readonly object padlock = new object();

 public static List<string> Sessions
 {
       get
       {
            return _sessions;
       }
  }

  protected void Session_Start(object sender, EventArgs e)
  {
      lock (padlock)
      {
          _sessions.Add(Session.SessionID);
      }
  }
  protected void Session_End(object sender, EventArgs e)
  {
      lock (padlock)
      {
          _sessions.Remove(Session.SessionID);
      }
  }

동기화 오버헤드를 낮추기 위해 일부 동시 수집을 사용하는 것을 고려해야 합니다.ConcurrentBag 또는 ConcurrentDictionary.또는 불변 목록

https://msdn.microsoft.com/en-us/library/dd997373(v=vs.110).aspx

https://msdn.microsoft.com/en-us/library/dn467185.aspx

이 정보를 제공하는 클래스나 방법이 없다는 것은 옳지 않은 것 같습니다.SessionStateStoreProvider의 기능을 사용하면 현재 활성 세션을 반환하는 방법을 사용할 수 있으므로 Jan Remunda가 언급한 session_start 및 session_end에서 세션 수명을 능동적으로 추적할 필요가 없습니다.

저는 모든 세션 목록을 얻을 수 있는 기본적인 방법을 찾을 수 없었고, Jan이 언급한 것처럼 세션 생활을 추적하고 싶지 않았기 때문에 결국 이 솔루션을 사용하게 되었고, 이것은 제 경우에 효과가 있었습니다.

public static IEnumerable<SessionStateItemCollection> GetActiveSessions()
{
    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)
                {
                    yield return sess;
                }
            }
        }
    }
}

http://weblogs.asp.net/imranbaloch/archive/2010/04/05/reading-all-users-session.aspx

작동 방식:

InProc 세션 데이터는 Icollection을 구현하는 ISessionStateItemCollection 구현에서 HttpRuntime의 내부 캐시에 저장됩니다.이 코드에서는 우선 HttpRuntime 클래스의 CacheInternalStaticProperty를 얻은 다음 이 객체의 도움으로 I 타입인 private member를 입력했습니다.그런 다음 이 사전을 열거하고 시스템 유형의 개체만 선택합니다.웹.세션 상태.ProcSessionState에서 마침내 각 사용자에 대한 SessionStateItemCollection을 가져왔습니다.

요약:.

이 글에서는 현재 사용자 세션을 모두 얻을 수 있는 방법을 보여줍니다.그러나 이 코드를 실행할 때 한 가지는 모든 페이지 이벤트 후에 세션이 저장되므로 현재 요청 컨텍스트에 설정된 현재 사용자 세션을 표시하지 않는다는 것입니다.

ASP.net 의 최신 버전에 대한 @jiitdh의 답변과 동일한 내용을 찾고 있었습니다. 아무것도 찾을 수 없어서 v4.6.2 솔루션으로 이 스레드를 업데이트하려고 했는데...최신 버전의 .net으로 테스트하지 않았지만 v4.5에서는 작동하지 않습니다.앞으로 v4.6.1과 호환이 될 것 같습니다.

Cache cache = HttpRuntime.Cache;
MethodInfo method = typeof( System.Web.Caching.Cache ).GetMethod( "GetInternalCache", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy );

object objx = method.Invoke( cache, new object[] { false } );

FieldInfo field = objx.GetType().GetField( "_cacheInternal", BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance );
objx = field.GetValue( objx );

field = objx.GetType().GetField( "_cachesRefs", BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance );
objx = field.GetValue( objx );

IList cacherefs = ( (IList)objx );
foreach( object cacheref in cacherefs )
{
    PropertyInfo prop = cacheref.GetType().GetProperty( "Target", BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance );

    object y = prop.GetValue( cacheref );

    field = y.GetType().GetField( "_entries", BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance );

    Hashtable c2 = (Hashtable)field.GetValue( y );
    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 )
            {
                // Do your stuff with the session!
            }
        }
    }
}

저는 ajitdh의 답변이 정말 마음에 듭니다.그에게 투표하세요.이 솔루션에 대한 또 다른 언급은 다음과 같습니다.

http://weblogs.asp.net/imranbaloch/reading-all-users-session

이것은 저를 가깝게 만들었지만, 제가 알고 있는 특정 세션 ID의 세션을 찾는 제 개인적인 목표는 달성하지 못했습니다.그래서 저는 제 목적상 세션아이디를 세션아이템으로 추가했을 뿐입니다(Session["이라고 말함).SessionId"] = 세션입니다.세션 시작 시 SessionId.)그 다음에 일치하는 값을 가진 세션을 찾았는데...저는 컬렉션 중 하나에 색인을 붙여 이 항목을 실제로 꺼내는 것을 선호했지만, 이것이 적어도 작동하게 만들었습니다.

물론, 이 모든 것은 인프로세스 세션을 위한 것으로, 저는 정말로 이 문제에서 벗어날 것을 고려하고 있습니다.

private static SessionStateItemCollection GetSession(string sessionId)
{
    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 o0 = entry.Value.GetType().GetProperty("Value", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(entry.Key, null);
            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["SessionId"] != null && ((string)sess["SessionId"]) == sessionId)
                    {
                        return sess;
                    }
                }
            }
        }
    }

    return null;
}

다음은 최근 30분 이내에 활성화된 로그온한 사용자의 목록을 가져오는 WebForms/Identity 예제입니다.

아래 답변은 단일 웹 서버에 적용되며, 응용프로그램이 재시작되면 캐시가 손실됩니다.데이터를 유지하고 웹 팜의 서버 간에 공유하려는 경우 이 답변이 흥미로울 수 있습니다.

Global.asa.cs 에서:

public static ActiveUsersCache ActiveUsersCache { get; } = new ActiveUsersCache();

그리고.

protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
    if (User != null && User.Identity.IsAuthenticated)
    {
        // Only update when the request is for an .aspx page
        if (Context.Handler is System.Web.UI.Page)
        {
            ActiveUsersCache.AddOrUpdate(User.Identity.Name);
        }
    }
}

다음 클래스를 추가합니다.

public class ActiveUsersCache
{
    private readonly object padlock = new object();
    private readonly Dictionary<string, DateTime> cache = new Dictionary<string, DateTime>();
    private DateTime lastCleanedAt;

    public int ActivePeriodInMinutes { get; } = 30;
    private const int MinutesBetweenCacheClean = 30;

    public List<ActiveUser> GetActiveUsers()
    {
        CleanCache();

        var result = new List<ActiveUser>();
        lock (padlock)
        {
            result.AddRange(cache.Select(activeUser => new ActiveUser {Name = activeUser.Key, LastActive = activeUser.Value}));
        }
        return result;
    }

    private void CleanCache()
    {
        lastCleanedAt = DateTime.Now;
        var cutoffTime = DateTime.Now - TimeSpan.FromMinutes(ActivePeriodInMinutes);
        lock (padlock)
        {
            var expiredNames = cache.Where(au => au.Value < cutoffTime).Select(au => au.Key).ToList();
            foreach (var name in expiredNames)
            {
                cache.Remove(name);
            }
        }
    }

    public void AddOrUpdate(string userName)
    {
        lock (padlock)
        {
            cache[userName] = DateTime.Now;
        }

        if (IsTimeForCacheCleaup())
        {
            CleanCache();
        }
    }

    private bool IsTimeForCacheCleaup()
    {
        return lastCleanedAt < DateTime.Now - TimeSpan.FromMinutes(MinutesBetweenCacheClean);
    }
}

public class ActiveUser
{
    public string Name { get; set; }

    public DateTime LastActive { get; set; }

    public string LastActiveDescription
    {
        get
        {
            var timeSpan = DateTime.Now - LastActive;
            if (timeSpan.Minutes == 0 && timeSpan.Seconds == 0)
                return "Just now";
            if (timeSpan.Minutes == 0)
                return timeSpan.Seconds + "s ago";
            return $"{timeSpan.Minutes}m  {timeSpan.Seconds}s ago";
        }
    }
}

마지막으로 활성 사용자를 표시할 페이지에서 결과를 표시합니다.

UserRepeater.DataSource = Global
    .ActiveUsersCache.GetActiveUsers().OrderByDescending(u => u.LastActive);
UserRepeater.DataBind();

내가 아는 한, 표준 인메모리 세션으로는 불가능합니다.이 문제는 지난 주에 제가 고민하던 것으로 세션 상태 서버를 사용하지 않는 한 불가능하다는 결론에 도달했습니다.디자인적인 면에서 보면 다소 이상해 보입니다. :/

당신은 또한 이것을 기본적인 것으로 시도할 수 있습니다, 이것은 단지 당신이 그 개념을 이해할 수 있도록 하기 위한 것입니다.

protected void Page_Load(object sender, EventArgs e)
    {
        if (Convert.ToInt32(Session["islogged"]) == 0)
        {
            Label1.Text = "you are not logged";
        }

    }

    protected void logged(object sender, EventArgs e)

/* 버튼을 클릭하면 로그인 버튼이 나타나도록 버튼에 추가*/ {

            Label1.Text = "you are  Logged in "; 


    }

다음 코드를 사용해 보십시오.

 for (int i = 0; i < Session.Keys.Count - 1; i++)
        {
            Label1.Text += Session.Keys.Get(i) + " - " + Session[i].ToString()+"<br/>";
        }

언급URL : https://stackoverflow.com/questions/1470334/list-all-active-asp-net-sessions