Liste Tous actifs ASP.NET séances

Comment puis-je énumérer (et itérer) tous les courants ASP.NET des séances?

41
demandé sur Alex 2009-09-24 12:04:45

7 réponses

Vous pouvez collecter des données sur les sessions dans global.événements asax Session_Start et Session_End (seulement dans les paramètres 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);
      }
  }

Vous devriez envisager d'utiliser certaines collections concurrentes pour réduire les frais généraux de synchronisation. ConcurrentBag ou ConcurrentDictionary. Or ImmutableList

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

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

33
répondu Jan Remunda 2016-11-11 15:18:24

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

Comment cela fonctionne :

les données de session InProc sont stockées dans le cache interne de HttpRuntime dans une implémentation de Isessionsteitemcollection qui implémente ICollection. Dans ce code, tout d'abord J'ai obtenu la propriété statique CacheInternal de la classe HttpRuntime et ensuite avec l'aide de cet objet j'ai obtenu _entries private member qui est de type ICollection. Ensuite, il suffit d'énumérer ce dictionnaire et ne prendre objet du système de type.Web.SessionState.Inprocessionstate et finally got SessionStateItemCollection pour chaque utilisateur.

Résumé :

Dans cet article, je vous montre comment vous pouvez obtenir toutes les Sessions utilisateur. Cependant, une chose que vous trouverez lors de l'exécution de ce code est qu'il n'affichera pas la Session utilisateur actuelle qui est définie dans le contexte de la requête actuelle parce que la Session sera sauvegardée après tout le La Page Des Événements...

19
répondu user711040 2016-10-01 16:29:34

il ne semble pas juste qu'il n'y ait aucune classe ou méthode qui fournisse cette information. Je pense que c'est une bonne chose d'avoir une fonctionnalité pour Sessionstatoreprovider, d'avoir une méthode qui retourne la session active en cours, de sorte que nous n'ayons pas à suivre activement la vie de session dans session_start et session_end comme le mentionne Jan Remunda.

comme je n'ai pas pu trouver de méthode hors de la boîte pour obtenir toute la liste des sessions, et je ne voulais pas suivre la vie de session comme mentionné par Jan, Je fin avec cette solution, qui a fonctionné dans mon cas.

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
répondu ajitdh 2012-03-14 16:47:20

j'aime vraiment la réponse d'ajitdh. Ne upvote lui. Voici une autre référence à cette solution:

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

Cela m'a fait fermer, mais il a échoué à atteindre mon objectif personnel de trouver la session pour un Id de session que je savais. Donc, pour mes besoins, j'ai juste ajouté le sessionid comme point de session (disons Session["SessionId"] = session.Id de session au Démarrage de la Session.) Ensuite, j'ai juste regardé pour une session avec une valeur correspondante... J'aurais préféré sortir cette entrée en indexant dans l'une des collections, mais cela l'a fait fonctionner au moins.

bien sûr, tout cela est pour les sessions en-Proc, dont je considère en effet s'éloigner.

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
répondu Greg 2015-03-09 13:19:23

voici un exemple de WebForms/Identity qui obtient une liste des utilisateurs connectés actifs au cours des 30 dernières minutes.

la réponse ci-dessous fonctionne pour un seul serveur web, et le cache sera perdu si l'application redémarre. Si vous voulez persister les données et les partager entre des serveurs dans une ferme web, cette réponse pourrait être intéressant.

Dans Global.asa.cs:

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

et

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

L'ajout de ces deux classes:

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

Enfin, dans la page où vous souhaitez afficher les utilisateurs actifs, d'afficher les résultats:

UserRepeater.DataSource = Global
    .ActiveUsersCache.GetActiveUsers().OrderByDescending(u => u.LastActive);
UserRepeater.DataBind();
1
répondu Phil Haselden 2017-06-21 06:01:42

à ma connaissance, avec des sessions de mémoire standard, vous ne pouvez pas. C'est quelque chose que je m'efforçais de faire la semaine dernière et je suis arrivé à la conclusion que ce n'est pas possible à moins que vous utilisiez un serveur d'état de session. Ça semble plutôt étrange du point de vue du design si vous me demandez. :/

0
répondu Nathan Taylor 2009-09-24 08:17:01

Essayez le code suivant

 for (int i = 0; i < Session.Keys.Count - 1; i++)
        {
            Label1.Text += Session.Keys.Get(i) + " - " + Session[i].ToString()+"<br/>";
        }
-16
répondu Himadri 2009-09-24 08:24:29