Reading All Users Session

  Introduction :

           InProc Session is the widely used state management. Storing the session state Inproc is also the fastest method and is well-suited to small amounts of volatile data. Reading and writing current user Session is very easy. But some times we need to read all users session before taking a decision or sometimes we may need to check which users are currently active with the help of Session. But unfortunately there is no class in .Net Framework (i don't found myself) to read all user InProc Session Data. In this article i will use reflection to read all user Inproc Session.

  Description :

             There is slight difference in code depending ASP.NET version( 2.0 and 3.5).

           This code will work equally in both MVC and webform, but for demonstration i will use a simple webform example. So let's create a simple Website and Add two aspx pages, Default.aspx and Default2.aspx. In Default.aspx just add a link to navigate to Default2.aspx and in Default.aspx.cs just add a Session.

Default.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <a href="Default2.aspx" mce_href="Default2.aspx">Click to navigate to next page</a>
    </div>
    </form>
</body>
</html>

Default.aspx.cs:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Session["User"] = "User" + DateTime.Now;
    }
}

Now when every user click this link will navigate to Default2.aspx where all the magic appears.

Default2.aspx.cs(2.0):

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Reflection;
using System.Web.SessionState;

public partial class Default2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        object obj = typeof(HttpRuntime).GetProperty("CacheInternal", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null, null);
        Hashtable c2 = (Hashtable)obj.GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);
        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["User"] != null)
                    {
                        Label1.Text += sess["User"] + " is Active.
"; } } } } } }

Default2.aspx.cs(3.5):

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Reflection;
using System.Web.SessionState;public partial class Default2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
            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["User"] != null)
                            {
                                 Label1.Text += sess["User"] + " is Active.
"; } } } } } } }

 

        Now just open more than one browsers or more than one browser instance and then navigate to Default.aspx and click the link, you will see all the user's Session data.

 

 

How this works :

        InProc session data is stored in the HttpRuntime’s internal cache in an implementation of ISessionStateItemCollection that implements ICollection. In this code, first of all i got CacheInternal Static Property of HttpRuntime class and then with the help of this object i got _entries private member which is of type ICollection. Then simply enumerate this dictionary and only take object of type System.Web.SessionState.InProcSessionState and finaly got SessionStateItemCollection for each user.

Summary :

        In this article, I shows you how you can get all current user Sessions. However one thing you will find when executing this code is that it will not show the current user Session which is set in the current request context because Session will be saved after all the Page Events.

18 Comments

  • Interesting article Imran.

    Arun

  • Hello Imran,

    I'm getting below error when i click on "Click to navigate to next page" and move to next page.

    Object reference not set to an instance of an object.
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

    Line 18: {
    Line 19: object obj = typeof(HttpRuntime).GetProperty("CacheInternal", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null, null);
    Line 20: Hashtable c2 = (Hashtable)obj.GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);
    Line 21: foreach (DictionaryEntry entry in c2)
    Line 22: {

    StackTrace --:

    [NullReferenceException: Object reference not set to an instance of an object.]
    MyTestProject.SessionSt2.Page_Load(Object sender, EventArgs e) in C:\Atul_Projects\MyTestProject\MyTestProject\SessionSt2.aspx.cs:20
    System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
    System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
    System.Web.UI.Control.OnLoad(EventArgs e) +99
    System.Web.UI.Control.LoadRecursive() +50
    System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627

  • The Problem is resolved
    Please check the code again

    Update from Kjell Ahlström on 04-05-2016:

    Hi Imran
    I wanted to thank you for this earlier post which really helped me out with an important problem:
    http://weblogs.asp.net/imranbaloch/reading-all-users-session

    I ran into the problem that some of the other users had when deploying to a server enviroment, and found the issue. The comments were disabled on that post since the post was so old, but I thought I'd mention the fix for you in case you'd like to update the old post or add a comment to help any future visitors who also might be in need of grabbing all sessions.

    Depending on cpu, .NET might choose different implementations for the CacheInternal.
    http://referencesource.microsoft.com/#System.Web/Cache/cache.cs,821
    The code provided works great when CacheMultiple is used, but when CacheSingle is used, grabbing the _caches field will cause an error since the field doesn't exist on CacheSingle. The fix is easy since the _caches field of CacheMultiple is a collection of CacheSingles. You only need to use the CacheInternal itself instead of grabbing the _caches collection when the _caches field doesn't exist.

  • I haven't gotten a chance to run this code yet but as soon as I have a moment I'm excited to do it. I'll probably port it to VB, if I do I'll post it here for posterity.

  • Here's my VB translation of your code. My initial test worked, I haven't used it other than that though. I went ahead and put it as a static method and return it as a list of the state collections.
    ----------------------------------------------------

    Imports System.Web.SessionState

    Public Class SessionInfo

    Public Shared Function GetAllSessions() As List(Of SessionStateItemCollection)

    Dim sessions As New List(Of SessionStateItemCollection)
    Dim obj As Object = GetType(HttpRuntime).GetProperty("CacheInternal", Reflection.BindingFlags.NonPublic + Reflection.BindingFlags.Static).GetValue(Nothing, Nothing)
    Dim obj2 As Object() = DirectCast(obj.GetType.GetField("_caches", Reflection.BindingFlags.NonPublic + Reflection.BindingFlags.Instance).GetValue(obj), Object())
    Dim c2 As Hashtable = obj2(0).GetType.GetField("_entries", Reflection.BindingFlags.NonPublic + Reflection.BindingFlags.Instance).GetValue(obj2(0))

    For Each entry As DictionaryEntry In c2
    Dim o1 As Object = entry.Value.GetType.GetProperty("Value", Reflection.BindingFlags.NonPublic + Reflection.BindingFlags.Instance).GetValue(entry.Value, Nothing)

    If o1.GetType.ToString = "System.Web.SessionState.InProcSessionState" Then
    Dim sess As SessionStateItemCollection = o1.GetType.GetField("_sessionItems", Reflection.BindingFlags.NonPublic + Reflection.BindingFlags.Instance).GetValue(o1)

    If sess IsNot Nothing Then
    sessions.Add(sess)
    End If
    End If
    Next

    Return sessions

    End Function

    End Class

  • I am having a weird occurance. Both my development machine and my server's web-site are running 3.5. This code works locally, but when it goes to the server the 3.5 version won't work on the 3.5 web-site (but 2.0 version will).

    I know my server is using 3.5 because I'm loading and using 3.5 assemblies... what am I missing that I should be looking at?

  • I will test this situation my self and let you know

  • @Kostkac,
    I have just tested with .NET 4.0. It is working fine. The only problem you may get is that this will not work in partial trust.

  • I've just implemented the VB 3.5 version of the code and it seemed to be working, but then I realized it only returns about half of the active session objects. If I create 11 different sessions I only get 5 returned by your code. I know the other sessions still exist because when I terminate the application forcing all sessions to end I can see all 11 sessions terminating in my Session_End() event.

    There does not seem to be any pattern to why certain sessions are dropped. I did noticed that the sessions are inserted into the internal cache randomly (not in the order they are created) and all of the sessions that are dropped by your code are at the end of the cache.

    Any idea what is causing this problem?

    Thanks, Scott.

  • Hi

    Iam trying this with .Net 2 and I still get an null object ref. I am sure I have the latest code for Default2.aspx.cs(2.0). Anyone else getting this issue or is it just me ?

  • Excellent, thankyou Imran, works a treat in .Net 2 now.

  • Hai,

    It is a great post. I have a problem but. When I run the application in my end. it works great , but when I gave the update to my client there is a NullReferenceException thrown in the below line.
    object[] obj2 = (object[])obj.GetType().GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);

    Can any one please help me to know as how to fix it

    Thanks
    Dhanajeyan.M

  • @Dhanajeyan,
    You need ReflectionPermission. Make sure application is running on FullTrust or any other trust level having ReflectionPermissions.

  • Same here, works fine on local dev but NullReferenceException is throw on the server around

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

    I've set the following in the web config

    and


    but no joy. What am I missing?

    Thanks,
    Jas

  • @Jas,

    It is working on my Windows 2008 R2, IIS 7. Make sure that Session Module is included. Put this in web.config.

  • Hi Imran! is there any idea how to close the session of one browser from other session.

  • @rkumar670, You can clear all sessions on server. But you will be not able to remove browser session on client.

  • Hats off..
    A good article which helped me a lot..
    Keep up the good work..

Comments have been disabled for this content.