Lista wszystkich aktywnych ASP.NET sesje

Jak mogę wymienić (i iterację) wszystkie bieżące ASP.NET sesje?

Author: Alex, 2009-09-24

7 answers

Możesz zbierać dane o sesjach w trybie globalnym.zdarzenia asax Session_Start i Session_End (tylko w Ustawieniach in-proc):

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);
      }
  }

Powinieneś rozważyć użycie niektórych współbieżnych kolekcji, aby obniżyć koszty synchronizacji. ConcurrentBag lub ConcurrentDictionary. Or ImmutableList

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

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

 33
Author: Jan Remunda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-11 15:18:24

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

Jak to działa:

Dane sesji InProc są przechowywane w wewnętrznej pamięci podręcznej HttpRuntime w implementacji ISessionStateItemCollection, która implementuje ICollection. W tym kodzie najpierw otrzymałem statyczną właściwość Cacheinternal klasy HttpRuntime, a następnie przy pomocy tego obiektu otrzymałem _entries Private member, który jest typu ICollection. Wtedy po prostu wylicz ten słownik i weź tylko obiekt typu System.Www.SessionState.InProcSessionState i ostatecznie dostały SessionStateItemCollection dla każdego użytkownika.

Podsumowanie:

W tym artykule, pokażę Ci, jak można uzyskać wszystkie bieżące sesje użytkownika. Jednak jedną rzeczą, którą znajdziesz podczas wykonywania tego kodu jest to, że nie wyświetli on bieżącej sesji użytkownika, która jest ustawiona w bieżącym kontekście żądania, ponieważ sesja zostanie zapisana po wszystkich zdarzeniach strony...

 19
Author: user711040,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-01 16:29:34

To nie wydaje się w porządku, że nie ma żadnej klasy lub metody, która dostarcza tych informacji. Myślę, że dobrze jest mieć funkcję dla SessionStateStoreProvider, mieć metodę, która zwraca bieżącą aktywną sesję, abyśmy nie musieli aktywnie śledzić życia sesji w session_start i session_end, o czym wspomniał Jan Remunda.

Ponieważ nie mogłem znaleźć żadnej niefrasobliwej metody, aby uzyskać listę wszystkich sesji, i nie chciałem śledzić życia sesji, jak wspomniał Jan, kończę z To rozwiązanie, które zadziałało w moim przypadku.

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;
                }
            }
        }
    }
}
 17
Author: ajitdh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-14 16:47:20

Bardzo podoba mi się odpowiedź ajitdha. Proszę go uprzedzić. Oto kolejne odniesienie do tego rozwiązania:

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

To mnie zbliżyło, ale nie udało mi się osiągnąć mojego osobistego celu znalezienia sesji dla konkretnego identyfikatora sesji , który znałem. Tak więc, dla moich celów, dodałem sessionid jako element sesji (powiedzmy Session["SessionId"] = session.SessionId na początku sesji.) Wtedy po prostu Szukałem sesji z pasująca wartość... Wolałbym wyciągnąć ten wpis, indeksując go do jednej z kolekcji, ale to przynajmniej sprawiło, że działał.

Oczywiście jest to wszystko dla sesji in-Proc, z których rzeczywiście rozważam odejście.

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;
}
 4
Author: Greg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-09 13:19:23

Oto przykład WebForms / Identity, który pobiera listę zalogowanych użytkowników aktywnych w ciągu ostatnich 30 minut.

Odpowiedź poniżej działa dla pojedynczego serwera www, a pamięć podręczna zostanie utracona, jeśli aplikacja zostanie ponownie uruchomiona. Jeśli chcesz utrwalić Dane i udostępnić je między serwerami w farmie internetowej, ta odpowiedź może być interesująca.

In Global.asa.cs:

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

Oraz

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);
        }
    }
}

Dodaj te kilka klas:

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";
        }
    }
}

Wreszcie na stronie tam, gdzie chcesz wyświetlić aktywnych użytkowników, wyświetl wyniki:

UserRepeater.DataSource = Global
    .ActiveUsersCache.GetActiveUsers().OrderByDescending(u => u.LastActive);
UserRepeater.DataBind();
 1
Author: Phil Haselden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-21 06:01:42

Z tego, co wiem, przy standardowych sesjach w pamięci nie możesz. To jest coś, z czym zmagałem się w zeszłym tygodniu i doszedłem do wniosku, że nie jest to możliwe, chyba że używasz serwera stanu sesji. Wydaje mi się to dość dziwne z punktu widzenia projektowania. :/

 0
Author: Nathan Taylor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-24 08:17:01

Wypróbuj następujący kod

 for (int i = 0; i < Session.Keys.Count - 1; i++)
        {
            Label1.Text += Session.Keys.Get(i) + " - " + Session[i].ToString()+"<br/>";
        }
 -16
Author: Himadri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-24 08:24:29