List all active ASP.NET Sessions

后端 未结 9 1767
情话喂你
情话喂你 2020-11-28 22:39

How can I list (and iterate through) all current ASP.NET sessions?

相关标签:
9条回答
  • 2020-11-28 23:01

    You can collect data about sessions in global.asax events Session_Start and Session_End (only in in-proc settings):

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

    You should consider use some of concurrent collections to lower the synchronization overhead. ConcurrentBag or ConcurrentDictionary. Or ImmutableList

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

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

    0 讨论(0)
  • 2020-11-28 23:02

    Here's a WebForms/Identity example that gets a list of the logged on users active within the last 30 minutes.

    The answer below works for a single web server, and the cache will be lost if the application restarts. If you want to persist the data and share it between servers in a web farm, this answer might be of interest.

    In Global.asa.cs:

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

    and

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

    The add these couple of 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";
            }
        }
    }
    

    Finally, in the page where you want to display the active users, display the results:

    UserRepeater.DataSource = Global
        .ActiveUsersCache.GetActiveUsers().OrderByDescending(u => u.LastActive);
    UserRepeater.DataBind();
    
    0 讨论(0)
  • 2020-11-28 23:05

    I've been looking around for an equivalent of @ajitdh's answer for later versions of ASP.net - couldn't find anything, so thought I'd update this thread with solution for v4.6.2... Haven't tested with later versions of .net, but it doesn't work with v4.5. I am guessing it will be compatible with v4.6.1 onward.

    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!
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 23:05

    you can also try this as something basic, this is only so you can understand the concept

    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)
    

    /* add it to a button so the looged in button when it is clicked this will appear*/ {

                Label1.Text = "you are  Logged in "; 
    
    
        }
    
    0 讨论(0)
  • 2020-11-28 23:06

    To the best of my knowledge, with standard in-memory sessions you cannot. This is something I was grappling with last week and I came to the determination that it isn't possible unless you are using a session state server. Seems rather odd from a design standpoint if you ask me. :/

    0 讨论(0)
  • 2020-11-28 23:15

    Try the following code

     for (int i = 0; i < Session.Keys.Count - 1; i++)
            {
                Label1.Text += Session.Keys.Get(i) + " - " + Session[i].ToString()+"<br/>";
            }
    
    0 讨论(0)
提交回复
热议问题