asp.net session state - asp.net

During Session Start, one has access to the Request object. How about Session End, does it still have access to the Request object ? For example I want to count how many browsers are currently connected to my application.
Edit 1 : If Session End doesn't have access to Request Object, what info does it have access to ? Session ID, etc ?
Edit 2 : If Session End cannot be used to track disconnections, how does one track disconnections in ASP.Net ?
Thanks

No, the Request object is not available in Session End.
Note too that Session End only fires when you call Session.Abandon() from code, not when a Session expires due to natural timeout or what-have-you. Consequently, it is not a reliable method to use for tracking disconnections.

Session_End will be fired if one is using InProc.
Session_End will be fired
1) after n minutes of inactivity (n = timeout value), or
2) if someone calls Session.Abandon()
Session_End doesn't get fired if one closes the browser.
Session_End requires session state to be set.
If one needs the original Request.Browser data, one should save it in Session State.
During Session_End, it has access to the Session State.

from the documentation
The Session_OnEnd event occurs when a
session is abandoned or times out. Of
the Server built-in objects, only the
Application Object, Server Object, and
Session Object objects are available.
Remarks
You cannot call the Server.MapPath
method in the Session_OnEnd script. By
default, Session_OnEnd runs as the
Anonymous User, as defined for the
application. In the event that there
isn't an Anonymous user, or the Logon
for the Anonymous user fails, the
OnEnd function will not be called, and
an event will be logged.

Related

When is ASP.NET session state persisted

When I store a value in a session and some exception occurs afterwards, the session state might not be persisted.
Session["MyKey"] = value;
throw new Exception("Test exception");
I found out that if I'm using InProc mode, the value gets persisted immediately, so if an exception occurs, it's stored anyway.
But if I switch to StateServer mode, the value will not get persisted if an exception occurs. I can write to the session, read it again from the session, but after an exception occurs, it's like all the changes I made to the session state in that request will be discarded (i.e. not persisted). And any future request will read the "old" state of the session.
At first I was thinking that it's related to the session cookie not being sent in response in case of the exception, but this behavior occurs for sessions that already exist and users already hold their identifiers. It also clearly differs from InProc to StateServer, while both of these approaches handle cookies the same way, it's just the persistance layer that is different.
How does the session state persistance work? At which point in the request lifecycle are the changes actually persisted to StateServer? Is it possible to force persisting of the session state, so it would be persisted even after an exception occurs?
The docs says
https://msdn.microsoft.com/en-us/library/system.web.httpapplication.releaserequeststate.aspx
HttpApplication.ReleaseRequestState Event. Occurs after ASP.NET finishes executing all request event handlers. This event causes state modules to save the current state data.

Do some functionality on session timeout

How can i write some code like maintaining timeout in database or logging task, when session get timeout automatically after specific time(default 20 mins).
You can use Session_OnEnd Event, you can find all the related methods and properties about Session Object (IIS)
Please have a look Session-State Events
Also there is good article about ASP.NET Session End Event Fires Immediately After Session Start

What is session invalidation?

Session invalidation means session destroying.So if session is destroyed,it indicates that server cant identify the client which has visited in previous.So now it creates a new session id for that client.
Is this right?If wrong tell me the correct procedure.
Calling HttpSession.invalidate() simply clears any object that is bound to it and marks it as invalid, so if you try to modify it afterward it will throw exceptions.
Once a session has been invalidated, the SessionID placed in a cookie on the client will be invalid too, and a new one will have to be created when a new session object is created. So the new Session will have a new ID.
This is usefull to handle for example login/logout. Sessions should always be invalidated at login to help prevent Session fixation attacks
Yes, absolutely right. Invalidating a session will mark the session as invalid and will be destroyed. If the client comes with the session id which has been invalidated a new session will be created.
session.inValidate():
If we are logging into gmail then at server side server will create session object
If we are calling session.inValidate() method means we are logged out since session object is destroyed by the server.

When's the earliest i can access some Session data in global.asax?

i want to check if the Session contains some key/value data, in my global.asax. I'm not sure when the earliest possible time (and method name) is, to check this.
thanks :)
I always believed Application_AcquireRequestState was the first event in Global.asax that could access the current session. It's definitely not Application_BeginRequest.
MSDN casually mentions that the session state is acquired during Application_PostAcquireRequestState event. I wish it was restated at the Life Cycle Overview page.
The latest you can access session state is in Application_PostRequestHandlerExecute, as it is saved by SessionStateModule during the next event Application_ReleaseRequestState.
You need to use BeginRequest (http://msdn.microsoft.com/en-us/library/system.web.httpapplication.beginrequest.aspx) as it is the first event fired on the HttpApplication object (which the Global.asax inherits).
You'll see more about the ASP.NET Application Lifecycle here - http://msdn.microsoft.com/en-us/library/ms178473.aspx (this is for IIS 5 & IIS 6).
According to link text, the earliest events in global.asax that you can access session objects is when global.asax fires Session_Start event
Session__Start: Fired when a new user visits the application Web site.
Session__End: Fired when a user's session times out, ends, or they leave the application Web site

"HttpContext.Current.Session" vs Global.asax "this.Session"

Recently, while working on some code for an ASP.NET project at work. We needed a tracking util to take basic metrics on user activity (page hit count etc) we would track them in Session, then save the data to DB via Session_End in Global.asax.
I began hacking away, the initial code worked fine, updating the DB on each page load. I wanted to remove this DB hit on each request though and just rely on Session_End to store all the data.
All of the tracking code is encapsulated in the Tracker class, including properties that essentially wrap the Session variables.
The problem is that when I executed Tracker.Log() in the Session_End method, the HttpContext.Current.Session in the Tracker code was failing with a NullReferenceException. Now, this makes sense since HttpContext always relates to the current request, and of course in Session_End, there is no request.
I know that Global.asax has a Session property which returns a HttpSessionState that actually seems to work fine (I ended up injecting it in to the tracker)..
But I am curious, how the hell can I get the same reference to the HttpSessionState object used by Global.asax from outside of Global.asax?
Thanks in advance guys, I appreciate the input. :)
To answer the original question better:
Background
Every single page request spins up a new Session object and then inflates it from your session store. To do this, it uses the cookie provided by the client or a special path construct (for cookieless sessions). With this session identifier, it consults the session store and deserializes (this is why all providers but InProc need to be Serializable) the new session object.
In the case of the InProc provider, merely hands you the reference it stored in the HttpCache keyed by the session identifier. This is why the InProc provider drops session state when the AppDomain is recycled (and also why multiple web servers cannot share InProc session state.
This newly created and inflated object is stuck in the Context.Items collection so that it's available for the duration of the request.
Any changes you make to the Session object are then persisted at the end of the request to the session store by serializing (or the case of InProc, the HttpCache entry is updated).
Since Session_End fires without a current request in-fly, the Session object is spun up ex-nilo, with no information available. If using InProc session state, the expiration of the HttpCache triggers a callback event into your Session_End event, so the session entry is available, but is still a copy of what was last stored in the HttpContext.Cache. This value is stored against the HttpApplication.Session property by an internal method (called ProcessSpecialRequest) where it is then available. Under all other cases, it internally comes from the HttpContext.Current.Session value.
Your answer
Since the Session_End always fires against a null Context, you should ALWAYS use this.Session in that event and pass the HttpSessionState object down to your tracing code. In all other contexts, it's perfectly fine to fetch from HttpContext.Current.Session and then pass into the tracing code. Do NOT, however, let the tracing code reach up for the session context.
My answer
Don't use Session_End unless you know that the session store you are using supports Session_End, which it does if it returns true from SetItemExpireCallback. The only in-the-box store which does is the InProcSessionState store. It is possible to write a session store that does but the question of who will process the Session_End is kind of ambiguous if there are multiple servers.
Global.asax implements HttpApplication - which is what you are talking to when you call this from within it.
The MSDN documentation for HttpApplication has details on how you can get hold of it in an HttpHandler for example, and then get access to the various properties on it.
HOWEVER
Your application can create multiple instances of HttpApplication to handle parallel requests, and these instances can be re-used, so just picking it up somehow isn't going to guarentee that you have the right one.
I too would also add a note of caution - if your application crashes, there's no guarentee that session_end is going to be called, and you'll have lost all the data across all sessions, clearly not a good thing.
I agree that logging on every page is probably not a great idea, but perhaps a halfway house with some asynchronous logging happening - you fire details off to a logging class, that every now and then logs the details you are after - still not 100% solid if the app crashes, but you're less likely to lose everything.
I think you already answered your own question: usually the Session property in Global.asax and HttpContext.Current.Session are the same (if there is a current request). But in the case of a session timeout, there is no active request and therefore you can't use HttpContext.Current.
If you want to access the session from the method called by Session_End, then pass it as a parameter. Create an overloaded version the Log() method, which takes a HttpSessionState as a parameter, then call Tracker.Log(this.Session) from the Session_End event handler.
BTW: you are aware that you can not rely on the session end event in any case? It will only work as long as you have the session state in-process. When using SQL server or StateServer to mange the session state, the session end event will not fire.
The Session_End event is raised only when the sessionstate mode is set to InProc in the Web.config file. If session mode is set to StateServer or SQLServer, the event is not raised.
use Session["SessionItemKey"] to get the session value.
Okay, I am in the same problem to track the session activity. Instead of using session_end event, I have implemented the IDisposable interface and destructor to my sessiontracker class. I have modified the Dispose() method to save the session activity to DB. I invoked the method obj.Dispose() when a user clicks the logout button. If user closed the browser by mistake, then GC will call the destructor while cleaning the objects (not immediately but for sure it will call this method after sometime). The destructor method internally execute the same Dispose() method to save the session activities into DB.
-Shan
Session is available in your Global.asax file, during the Session_Start event. Maybe wait until this point to do stuff?
Remember that Session_End runs when the session times out without activity. The browser doesn't originate that event (because it's inactive), so the only time you actually will get the event is when using the InProc provider. In EVERY OTHER provider, this event will never fire.
Moral? Don't use Session_End.

Resources