Determine if ASP.NET's Session Object has timed out
ASP.NET allows you to pass data, specific to a given user, between web pages
using the Session object as it did in prior
versions of ASP. This works great since you can store anything in it. My
advise, though, is don't use it. It won't work on web farms and has problems
when multiple web sites are hosted in virtual directories under IIS.
Also, ASP.NET uses a rolling timeout feature which discards a user's session
information if no request is seen within the timeout period. The default, set
in the web.config, is 20 minutes which is reset with each request.
If the session times out and you try to reference a previously set value in code
without checking first, you get the "Object reference not set" exception. Thus,
always check as shown:
'Add a value to the Session object.
Session.Add("MyValue", "ABC")
...
If Session.Item("MyValue") Is Nothing Then
strValue = "XYZ" 'default value
Else
strValue = Session.Item("MyValue").ToString()
End If
So, why not just increase the timeout in the <system.web\sessionState>
item in the web.config? Because you may not want to increase the timeout period
for security reasons and other things can still pull the rug out from the
session object. For example, when running IIS 6 and the idle timeout property
of the worker process causes the entire process to end. So, you need to
know when session timeouts occur.
First, here is how the session is implemented. The HTTP protocol used by web
browsers to get files from web servers is stateless but ASP.NET needs to
know which requests came from the same user. The main way to do this is though
a non-persistent cookie, issued by the web server, that contains a
Session ID value. The ID is used to to access the user's specific
data.
The session object is implemented by the HTTP module System.Web.SessionState.SessionStateModule,
which executes before any of the .aspx page's events. SessionStateModule uses
the EnableSessionState attribute from the
@Page directive to see if it needs to get the user’s session
information. If EnableSessionState is true, the default, the module gets all of
the user’s session data and sets the Session property of the Page class to an
instance of the HttpSessionState class.
Note that a cookie-less method of sessions can be implemented in ASP.NET where
the session ID is embedded in the URL. The Session information can be stored
in-process in the web server's memory, the default, with a state service, or a
SQL Server database. This page discusses in-process storage, but applies to the
other methods as well.
Here's what happens when a user requests an ASP.NET web page. If the page's
EnableSessionState value is true, the session module adds the
ASP.NET_SessionId cookie to the response. On subsequent requests to
the same web site, the browser supplies the ASP.NET_SessionId cookie which the
server side module uses to access the proper user’s information.
The ASP.NET HttpSessionState class has an IsNewSession
method that returns True if a new session was created for this request. But to
detect a session timeout, you also must look for the ASP.NET_SessionId cookie
in the request because you want to know if it is a timeout and not a new
session as when the application starts. If this is a new session but the cookie
is present, the session has timed out.
You need to do this check in every page that uses the session object. An easier
way is to have all of your pages inherit from a base
page and perform the check there.
Inheriting from a base page instead of System.Web.UI.Page:
Public Class MyPage
Inherits MyBasePage
...
End Class
Base page code to check for session timeouts:
Public Class MyBasePage
Inherits System.Web.UI.Page
...
Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
' Call the base OnInit method.
MyBase.OnInit(e)
If Not Context.Session Is Nothing Then
If Session.IsNewSession Then
Dim strCookieHeader As String = Request.Headers("Cookie")
If Not strCookieHeader Is Nothing Then
If strCookieHeader.ToUpper().IndexOf("ASP.NET_SESSIONID") >= 0 Then
'On timeouts, redirect user to timeout page.
Response.Redirect("MyTimedOutPage.aspx")
End If
End If
End If
End If
End Sub
End Class
When multiple web sites are hosted in virtual directories. The ASP.NET_SessionId
cookie has a default path of "/" which means that the browser will send it to
ALL virtual directories hosted in the same IIS site. One way to solve this is
to adjust the cookie created by ASP.Net to set the path to the virtual
directory for the particular application. Then the browser will not send it to
other virtual directories. The cookie can be adjusted in the Global.asax file.
Adjusting the path of the ASP.NET_SessionId cookie:
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' Fires when the session is started
Dim oCookie As HttpCookie = Response.Cookies("ASP.NET_SessionId")
If Not oCookie Is Nothing Then
oCookie.Path = Request.ApplicationPath.ToLower()
End If
End Sub
|