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.

Published Monday, April 5, 2010 11:35 PM by imran_ku07
Filed under: , ,

Comments

# re: Reading All Users Session

Monday, April 5, 2010 11:45 PM by Arun Mahendrakar

Interesting article Imran.

Arun

# re: Reading All Users Session

Tuesday, April 6, 2010 2:59 AM by Atul

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

# re: Reading All Users Session

Tuesday, April 6, 2010 4:10 AM by imran_ku07

The Problem is resolved

Please check the code again

# re: Reading All Users Session

Friday, April 9, 2010 7:31 PM by BP

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.

# re: Reading All Users Session

Sunday, April 11, 2010 10:03 PM by BP

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

# re: Reading All Users Session

Tuesday, April 27, 2010 12:58 PM by BP

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?

# re: Reading All Users Session

Tuesday, April 27, 2010 1:31 PM by imran_ku07

I will test this situation my self and let you know

# re: Reading All Users Session

Tuesday, June 7, 2011 7:59 AM by Kostkac

I have sess property null for all FieldInfos. And Im using .NET 4.0. Do you have any idea?

# re: Reading All Users Session

Wednesday, June 8, 2011 2:02 PM by imran_ku07

@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.

# re: Reading All Users Session

Wednesday, June 8, 2011 2:40 PM by snsprint

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.

# re: Reading All Users Session

Monday, June 13, 2011 6:00 AM by Mike

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 ?

# re: Reading All Users Session

Monday, June 20, 2011 3:28 AM by Mike

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

# re: Reading All Users Session

Thursday, June 30, 2011 11:44 AM by Dhanajeyan

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

# re: Reading All Users Session

Friday, July 1, 2011 1:49 AM by imran_ku07

@Dhanajeyan,

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

# re: Reading All Users Session

Monday, August 8, 2011 8:45 AM by Jas

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

   <trustLevel name="Full" policyFile="internal"/>

and

   <trust level="Full" processRequestInApplicationTrust="true" />

but no joy. What am I missing?

Thanks,

Jas

# re: Reading All Users Session

Thursday, August 11, 2011 6:34 AM by imran_ku07

@Jas,

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

<modules runAllManagedModulesForAllRequests="true"/>

# re: Reading All Users Session

Friday, May 18, 2012 6:59 AM by rkumar670

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

# re: Reading All Users Session

Saturday, May 19, 2012 3:53 AM by imran_ku07

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

# re: Reading All Users Session

Tuesday, July 31, 2012 2:22 AM by Ash

Hats off..

A good article which helped me a lot..

Keep up the good work..