How long since a session was last accessed?

  • Thread starter Thread starter DamienS
  • Start date Start date
D

DamienS

Hi,

Can someone please tell me, is there an easy way to determine how long
since a session was last accesed? (or, to put it another way, how long
until timeout)?

Thanks very much in advance,



Damien
 
re:
!> Can someone please tell me, is there an easy way to determine how long
!> since a session was last accesed? (or, to put it another way, how long until timeout)?

There isn't any.




Juan T. Llibre, asp.net MVP
asp.net faq : http://asp.net.do/faq/
=========================
 
Well, the answer would be "just now".

If you have access to the Session object that means you are in ASPX page.
If you are in ASPX page that means it was just "accessed" and the timeout
will happen in 20 minutes from now

George.
 
re:
!> the timeout will happen in 20 minutes from now

Only if the default timeout value hasn't been modified.




Juan T. Llibre, asp.net MVP
asp.net faq : http://asp.net.do/faq/
=========================
 
Hi All,

I achieved what I wanted using a HTTPModule. Of course, you need to
register the module in web.config as well.



using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Web.SessionState;
using RPM;
using RunOnline.Enums;

namespace RunOnline.HTTPModules
{
public class clsSessionTracker : IHttpModule
{
HttpApplication _applicateion;

public void Dispose()
{

}

public void Init(HttpApplication context)
{
_applicateion = context;
context.PostAcquireRequestState += new EventHandler
(context_PostAcquireRequestState);
}

void context_PostAcquireRequestState(object sender, EventArgs
e)
{
HttpContext context = _applicateion.Context;
bool RequiresSession =
clsGlobalStaticFunctions.ClassHasInterface(
context.CurrentHandler.GetType(), typeof
(global::System.Web.SessionState.IRequiresSessionState));
if (RequiresSession)
{
((HttpApplication)sender).Session
[eSession.SessionLastAccessedTime.ToString()] = DateTime.Now;
((HttpApplication)sender).Session
[eSession.lastAccessedPage.ToString()] = context.Request.RawUrl;
}
}
}
}



.... and the supporting ClassHasInterface function.


static public bool ClassHasInterface(Type T, Type TInt)
{
return (T.GetInterface(TInt.FullName) != null);
}
 
Won't the time left for the session's timeout be reset to
the default timeout value every time that module runs ?




Juan T. Llibre, asp.net MVP
asp.net faq : http://asp.net.do/faq/
=========================
 
It seems to me that it would be better for you to tell us what you want...
One smart person i knew was saying that if you can explain what you want
then you are 50% done solving the problem.

Thanks
George.
 
Hi All.

Sorry if that was a little confusing as, in haste, I only posted half
the answer.

My original question was - "Can someone please tell me, is there an
easy way to determine how long since a session was last accesed? (or,
to put it another way, how long until timeout)? "

The goal behind all this was to create a system page that shows who is
logged in and how long they've been logged in for.

My first question - "determine how long since a session was last
accesed? "
This is 'hard'... and is what my posted code achieved (well, it worked
for me!)

My Second question - "(or, to put it another way, how long until
timeout)? "
This is easily derived once you have the first part... it's just the
session timeout time (set in web.config) minus the answer to the first
question.

The full solution involved me creating a collection class based on
KeyedCollection<,> and storing this at the Application level. When a
user logs into the site, a reference to their session is added to that
collection, using the sessionID as the key. Also, I use the
session_end event from global.asax to remove the ending session from
the collection when there session expires.

Every time the user makes a HTTP request, the httpmodule code I posted
yesterday runs, copying the 'now' time into a variable and storing
that into the session object for that particular session. I also store
the last page they accessed in a similar fashion.

It's then a simple matter on my 'display users' page to grab the
collection from the Application level and loop thorugh all of the user
sessions. I subtract SessionLastAccessedTime from the current time to
find the time of inactity. As mentioned above, the time to session
expiry is easily calculated.

It works well.

I hope that all makes sense.


Damien




Won't the time left for the session's timeout be reset to
the default timeout value every time that module runs ?

Juan T. Llibre, asp.net MVP
asp.net faq :http://asp.net.do/faq/



I achieved what I wanted using a HTTPModule. Of course, you need to
register the module in web.config as well.
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Web.SessionState;
using RPM;
using RunOnline.Enums;
namespace RunOnline.HTTPModules
{
   public class clsSessionTracker : IHttpModule
   {
       HttpApplication _applicateion;
       public void Dispose()
       {
       }
       public void Init(HttpApplication context)
       {
           _applicateion = context;
           context.PostAcquireRequestState += new EventHandler
(context_PostAcquireRequestState);
       }
       void context_PostAcquireRequestState(object sender, EventArgs
e)
       {
           HttpContext context = _applicateion.Context;
           bool RequiresSession =
clsGlobalStaticFunctions.ClassHasInterface(
              context.CurrentHandler.GetType(), typeof
(global::System.Web.SessionState.IRequiresSessionState));
           if (RequiresSession)
           {
               ((HttpApplication)sender).Session
[eSession.SessionLastAccessedTime.ToString()] = DateTime.Now;
               ((HttpApplication)sender).Session
[eSession.lastAccessedPage.ToString()] = context.Request.RawUrl;
           }
       }
   }
}
... and the supporting ClassHasInterface function.
       static public bool ClassHasInterface(Type T, Type TInt)
       {
           return (T.GetInterface(TInt.FullName) != null);
       }- Hide quoted text -

- Show quoted text -
 
My understanding of that was that you were looking for a way to interrogate
session objects themselves directly...



Well, I was kind of expecting to do that, however, on realising that
there was no built in property of the session object that did the job,
elected to store the property in the session 'array' (is that what
it's called?)



Presumably, if they don't proceed any further than the login page, nothing
gets added to the collection, even though a session has actually been
created...?

Yep. A little bit to my frustration actually! The original intention
was the capture the session start event and add the session to the
collection then, however, there was a problem that I couldn't get
around where it appeared that the session which was added to the
collection was not the same object as the session which they
eventually logged in under (I'm not sure if that makes much sense). I
note that you've mentinoed below that session IDs are not guaranteed
to be unique. I havevn't clicked that link yet, but, if it's referring
to the regenerateExpiredSessionId property of a session, then I played
around with that as well.

I've just read that link you sent. I'm now wondering if the problem I
was having above was due to this. I can't remember if I was testin
IsNewSession or not.... (it was late in the day and I was tired!!)
Also, bear in mind that SessionID values are not guaranteed to be unique in
every instance:http://www.google.com/search?q="ASP.NET"+SessionID+unique&rls=com...

Noted.


Luckily you're using inproc sessions... :-)

Indeed :-)

For the record, I had MAJOR headaches with this as well. Ideally, the
end event should've been captured in a HTTPModule. I'm stuffed if I
could get it working though. I found an article (http://codebetter.com/
blogs/karlseguin/archive/2006/06/12/146356.aspx) that touches on the
issues, (search for "There's a way to hook into those events, but as
far as I know, it's something of a nightmare" in the feedback).

I reckon that this is a bug in the framework. It was 'unnaceptably'
difficult (impossible for me anyway) to catch a reliable end event in
a httpmodule. I had to resort to the 'ugly' global.asax.
Presumably your site has a logout facility which tears down the session
causing Session_End to fire? Obviously, if a user simply closes their
browser (or moves to another site) without explicitly logging out, this
won't fire so at that point it will appear that they are still logged in
even though they are no longer using your site...


Correct. As you'd expect, it 'eventually' fires when the session
timesout and their session is removed. This is exactly the reason why
I wanted to find out how long they'd been inactive. The whole point of
this excercise was to find out how many were using the site at a given
time so that we could 'sneak in' an unscheduled site restart /
upgrade. If someone's logged in, but not accessed a page for 10
minutes, then I'm happy to reset the app and bounce their session.


How do you work out who is logged in i.e. which SessionID relates to which
user...?
Do you store their UserID / SAMAccountName in the collection too...?

When they log in, I create an instance of clsUserSession (below).
This takes their session object as a constructor.

I then add them to a keyedcollection (clsSessionBank) that is stored
in the Application array. They key for this is their sessionID. I can
loop through this and read the Session property to get access to the
Session array. There are also properties on clsUserSession that read
the Session array (LastAccessedTime).

/// <summary>
/// Used to wrap session variables for online user tracking.
/// </summary>
public class clsUserSession
{
private HttpSessionState _session;
private string _ip;
public clsUserSession(HttpSessionState session, string IP)
{
_session = session;
_ip = IP;
}

public DateTime LastAccessedTime
{
get
{
if(_session[eSession.SessionLastAccessedTime.ToString
()]==null)
{
return new DateTime(1, 1, 1);
}
else
{
return ((DateTime)_session
[eSession.SessionLastAccessedTime.ToString()]);
}
}
}

public HttpSessionState Session
{
get
{
return _session;
}
}
.....
}



public class clsSessionBank : KeyedCollection<string, clsUserSession>
{

int _maxSimultaneous = 0;
protected override string GetKeyForItem(clsUserSession item)
{
return item.Session.SessionID;
}

protected override void InsertItem(int index, clsUserSession
item)
{
base.InsertItem(index, item);
_maxSimultaneous = System.Math.Max(_maxSimultaneous,
this.Count);
}

public int MaxSimultaneous
{
get
{
return _maxSimultaneous;
}
}
}





What is the purpose of that...?


Now that you mention it, absolutely none!! :-)

Actually, that's not really true actually. The other day, I had a user
in there that was idle for 10 minutes (which, normally, I'd consider
safe to bounce). However, because I display the page he's on, I could
see that he was filling in a 'feedback form'.... hence, assumed he was
typing. As it turned out, at 13 minutes, he submitted the form, then
logged out. I guess it's a good thing I didn't bounce him!
 
Back
Top