Session Q&A

Posted on February 26, 2006  |  

Posted in Development

19 comments

Session storage has been around for so long that we take it for granted. However, working with the Session object has some nuances you don’t see documented in books. In this Q&A post I’d like to go over some issues you need to be aware of when relying on Session for short-term storage.

To limit this discussion to a reasonable scope, let’s assume we use only in-proc sessions. Storing session data in an out-of-proc state service or SQL Server is a different can of worms. Also, we won’t be talking about cookie-less sessions. They are a very strange beast.

One final disclaimer. I’m focusing on 1.x and realize that 2.0 has some enhancements some of which I will mention.

Q: Where is session ID stored?

A: When you first hit an ASP.NET-powered site, a non-expiring cookie with the name of ASP.NET_SessionId is issued (in 2.0 you can set a different cookie name in web.config). This cookie contains a randomly generated 20-something-character string which is the session ID and is sent with every request.

Here’s a very important point: the cookie will stay alive until you close your browser. In other words, the session ID will remain the same even if you navigate away to another site, say to check team standings at the Olympics, and then come back: if it’s the same browser window, the cookie will still be there and the session ID will be the same.

It’s possible to ditch a session by calling Session.Abandon() which will finish processing the page and only then clear out the session data. A subsequent page request causes a brand new session object to be instantiated. The session cookie is a staunch one—it stays intact even when Session.Abandon() causes one session object to die and another one to be born.

You can also let a session expire. The timeout interval is set in the <sessionState> section of web.config. When a session times out, it flushes all session data, the session object dies and a new one is born on a subsequent page hit. This is similar to the scenario with Session.Abandon() above. Even in this case the session cookie stays intact.

So here’s the conundrum: a session, essentially, is the time between the first page hit and the time when the browser window is closed. The fact that you can’t disable session timeout makes no sense to me. Basically, a user keeps his/her browser window open, but the session data may disappear due to a timeout. I wish there was a way to just let the session live for as long as the user has the browser running. Otherwise you end up with a predicament explained in the following section.

Q: Is there a way to tell if the session timed out or was abandoned?

A: There’s no simple answer to this. HttpSessionState has a handy property, IsNewSession which indicates whether the session was created with the current request. In other words, if you called Session.Abandon() or let it time out, your old session data will be gone, you will receive a brand new session object and Session.IsNewSession will be true the first time you hit a page.

I don’t know if it’s possible to tell which of the two things happened. Bob Boedigheimer shows how to at least detect session timeouts. I even rolled his code into a base class property to guard for this edge case.

The important point here is that you can never assume that if you’re stored something in session, it’ll be there the next time you go looking for it. A user may simply walk away from the computer and cause your session to expire. Again, these session timeouts seem nonsensical to me, but I don’t know if it’s possible to turn them off. Most likely not.

What you need to remember is to use code similar to Bob’s to detect if the session is gone. At this point you have two options:

  • re-read data and store it back in session, or
  • redirect to some page which politely notifies of the timeout and suggests to go back and do whatever the user was previously doing.

Q: Does presence (or absence) of global.asax affect the session ID?

A: Yes. Suppose you create a brand new web project without global.asax. After all, it’s perfectly normal to leave this file out if you don’t need it. Without global.asax your session cookie will be killed at the end of each page request, and a new one created on every subsequent request. This is to say the session ID will change with every page hit.

Now, suppose you add a blank global.asax. Does this help? No. The session ID will still change until you add an empty Session_Start() handler. If you dig long and hard with Reflector, you’ll see why the mere presence of this particular event handler guarantees that the session cookie will remain intact once it’s issued on first page hit.

Q: I don’t want global.asax in my project. Is there something I can do about the flaky session ID?

A: If you don’t want to drag around global.asax and need to "lock in" a session ID, your landing page needs to store something in session.

Here’s an example. Page a.aspx has no dealings with the session. Page b.aspx, on the other hand, stores something in session at least once. As long as you hit a.aspx, the session ID will change. As soon as you navigate to b.aspx, the session ID will "lock in" and remain constant until you close the browser.

To learn about the mechanics of it point your Reflector to the SessionStateModule class. MSDN has more on this, too:

When using cookie-based session state, ASP.NET does not allocate storage for session data until the Session object is used. As a result, a new session ID is generated for each page request until the session object is accessed. If your application requires a static session ID for the entire session, you can either implement the Session_Start method in the application’s Global.asax file and store data in the Session object to fix the session ID, or you can use code in another part of your application to explicitly store data in the Session object.

Q: The session cookie seems to be very resilient. Still, is there a way to discard it and obtain a new session ID?

A: The session cookie is a die-hard indeed. Microsoft’s Knowledge Base article How and why session IDs are reused in ASP.NET shows a dirty hack which forces the session ID to change. Don’t try this at home.

Q: When is Session_OnEnd called?

A: The runtime invokes Session_OnEnd, which you declare in global.asax, when you call Session.Abandon() or the session times out.

This leads to an interesting implication: does the session end immediately when the browser is closed (and, consequently, the session cookie goes away)? No, there’s no reliable way to detect when the user closes his/her browser.

The session manager stores session data in HttpCache with a sliding expiration. This expiration timeout is set in the <sessionState> of web.config. When the browser window is closed, the session is bound to expire because there’s no way to go back to using the session ID that just went away (unless you spoof the session, but we won’t discuss a movie-plot terrorist threat).

When the timeout is up, HttpCache will remove the session state object and invoke a callback which, essentially, translates into calling Session_OnEnd. Note that this happens way after the browser window is closed, but it does happen. Remember, you cannot access HttpContext is this handler, but the outgoing Session object is still alive. If you need to do some clean-up, Session.SessionID is still available.

Further Reading

There’s a great article by Michael Volodarsky at MSDN entitled Fast, Scalable, and Secure Session State Management for Your Web Applications which I highly recommend as a crash course in session management. Pay attention to the idea of "flattening" session data and breaking it down to storing only primitives. The discussion of partitioning and securing session state is very educational too.

One of the most important points of this article follows below:

Note that if you turn off session state in your application, the HttpContext.Session property will throw an exception if the page or handler tries to access it. If you mark the page as read-only, updates to the session in the out-of-process modes will not be preserved across requests. In InProc mode, however, updates will be preserved because they are made to the live objects that stay memory-resident across requests.

In other words, if you retrieve an object from Session and change any of its properties, you modify a live object and these changes are "committed" to the session even if the session is marked as read-only!

Conclusion

This improvised Q&A session is something I’ve been dealing with lately. I spent many hours Reflect’ing and experimenting, and figured I’d share my observations. Session state is a very helpful storage, but it will break you if you abuse it.

19 comments

Jingaling
on June 23, 2006

holy cow! you have to be kidding! if this is the kind of information on this site, i'll make sure to avoid it from now on.

"Again, these session timeouts seem nonsensical to me, but I don’t know if it’s possible to turn them off. Most likely not."

so you just want session info to stay around forever? don't you think that would tax memory just a tad? oh wait, you want to get rid of it when the user closes their browser. and how exactly do you expect to know about that on the server? and what about security? you want all those sessions just hanging around to be hijacked. Wow!


Milan Negovan
on June 23, 2006

I'm speaking from a pragmatic point of view. We've run into plenty of problems trying to keep up with session time-outs. Apparently, you've never dealt with these issues.

If you plan on leaving other comments showing lack of proper respect, then yes---I'm afraid you'll have to avoid this site. Comments, offensive toward me or other readers/posters, get deleted.


bhushan
on November 29, 2006

how can i clear session data if all i have is session ID?


Milan Negovan
on November 29, 2006

See if KB 899918 answers your question.


rameshbabu
on February 21, 2007

Hi,its veryhelpful for me,and also I have a problem with session_end while closing the browser.
Actually my requirement is show the online users in my website.if the user closed browser without logout also session_end have to fire.It working in my local system.But not working in remote.is need to changes any configuration settings in web.config or machine.config?


TurboBH
on March 7, 2007

My web app use session to store some objects, but sometime when I refresh the webpage, the session data lost and session.IsNewSession change to "True" while the the session.sessionID does not change.

Do you known why?


Mehul
on April 3, 2007

Hi,
This post is very helpful.
I am facing some problem with HttpContext.Session.IsNewSession property.This property works fine with request made to managed content(.aspx page).But when i make request to unmanaged content
(any image) this property returns null.

Is it the case that HttpContext.Session is not avilable for request made to unmanaged content.

Any inputs on this would be very helpful.


Milan Negovan
on April 4, 2007

If you're doing it inside of a custom HTTP handler, you need to mark it with the IRequiresSessionState interface.


Bhanu
on June 20, 2007

Hi,

I have used the method session.abandon() in a web service and i'm calling it in the client side function with Pagemethods using script manager tag but still it is not firing the event session_end. I'm unable 2 understand y its not getting fired. Please help me out.

Thanks in advance...
Bhanu


Josh Stodola
on August 1, 2007

No matter what I do, Session_End will not fire on our production IIS server(s). Yes we use InProc, yes we have data in the session. The servers are not exactly top notch, they are running windows 2000 with IIS 5.1. In development, I can get the Session_End event to fire as expected. But as soon as I get it on IIS, it does not do anything.

I have scoured Google, many forums and news groups, and I am reading all the same junk over and over. Since it works in developement, I have to assume that IIS is the culprit. But, I have no idea what it could be.

Any ideas?!


Milan Negovan
on August 3, 2007

Josh, has this article been of any help?


Suresh Gopalakrishnan
on June 10, 2008

Is there a way to abandon the session for my application when navigating to another site without closing the browser?


Milan Negovan
on June 13, 2008

There's Session.Abandon() but I've had problems with it in the past. There was something with it messing up my logout routine, so I use Session.Clear() instead.


Rishi
on September 15, 2008

i hav very strange problem .. i dont know it linked with sessions or not...
when i close my first web site without logging out...
after that if i will open second (other) web site.. Menu of second site disappears...

again if i open my first site and then logged off ....
this time second site work well .....
(both site using asp.net 2.0)


aliwajdan
on February 9, 2009

I have a strange problem with session
i have developed a web application with master pages. there is a control on master page displaying the categories from database. this control is using session variables to show/hide the levels of menu. when i first time visit it and click the category to expand it does not but the event is fired. content page is loaded. it is working fine on local server. but it is not working on live server for first click on second click it is working fine.
here is the link
www.douglas.com
click on pc/104
the content page is updated but the menu is not loaded for first time

can you please help?
i'll be thank full


Milan Negovan
on March 2, 2009

I'm not sure that you mean. I see both the top and side navigation load fine.


HL
on August 12, 2009

May I know what will happen the next time they access the same page (after shut down the pc) if session.abandon was not trigger (because user directly close the browser instead of click the sign-out button where session.abandon is coded) ? Do they get back the same session ID?


Milan Negovan
on August 12, 2009

Each session is tied to a cookie which doesn't persist browser restarts. Therefore you will never have the same session ID.


jay doshi
on January 20, 2010

i want the ans about where actually SESSION ID is stored??
(1)IN COOKIES OR (2)IN SESSION STATE..
REPLAY ME VIA MAIL IF POSSIBLE>>>>