Session State Management in Application having ASP and ASP. Net Pages

If we are developing a web application in which both ASP and ASP.NET pages resides, then passing session information from ASP to ASP.NET page or vice versa becomes a critical issue. To share session state between ASP and ASP.NET pages, session state need to be stored in some common format like in database.


If we are developing a web application in which both ASP and ASP.NET pages resides, then passing session information from ASP to ASP.NET page or vice versa becomes a critical issue.

To share session state between ASP and ASP.NET pages, session state need to be stored in some common format like in database.

In the following example, ASP and ASP.NET session states are stored in Microsoft SQL Server database.

ASP.NET implementation

In ASP.NET, every Web page derives from the System.Web.UI.Page class. The Page class aggregates an instance of the HttpSession object for session data. In this example, a custom Page class called SessionPage is derived from the System.Web.UI.Page to offer all the same features as the Page class. The only difference with the derived page is that the default HttpSession is overridden with a custom session object. (Using the new modifier for the instance variable, C# allows the derived class to hide members of the base class.)

[Serializable]
public class mySession
{
private HybridDictionary dic = new HybridDictionary();
public mySession()
{
}
public string this [string name]
{
get
{
return (string)dic[name.ToLower()];
}
set
{
dic[name.ToLower()] =
value;
}
}
}

The Page class exposes different events and methods for customization. In particular, the OnInit method is used to set the initialize state of the Page object. If the request does not have the mySession cookie, a new mySession cookie will be issued to the requester. Otherwise, the session data will be retrieved from SQL Server using a custom data access object, SessionPersistence. The dsn and SessionExpiration values are retrieved from the web.config.

override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
cookie =
this.Request.Cookies[sessionPersistence.SessionID];
if (cookie == null)
{
Session =
new mySession();
CreateNewSessionCookie();
IsNewSession =
true;
}
else
Session = sessionPersistence.LoadSession(Server.UrlDecode(cookie.Value).ToLower().Trim(), dsn, SessionExpiration);
this.Unload += new EventHandler(this.PersistSession);
}
private void CreateNewSessionCookie()
{
cookie =
new HttpCookie(sessionPersistence.SessionID, sessionPersistence.GenerateKey());
this.Response.Cookies.Add(cookie);
}

The SessionPersistence class uses the BinaryFormatter of the Microsoft .NET Framework to serialize and deserialize the session state in binary format for optimal performance. The resulting binary session state data can then be stored in the SQL Server as an image field type.

public mySession LoadSession(string key, string dsn, int SessionExpiration)
{
SqlConnection conn =
new SqlConnection(dsn);
SqlCommand LoadCmd =
new SqlCommand();
LoadCmd.CommandText = command;
LoadCmd.Connection = conn;
SqlDataReader reader =
null;
mySession Session =
null;
try
{
LoadCmd.Parameters.Add("@ID",
new Guid(key));
conn.Open();
reader = LoadCmd.ExecuteReader();
if (reader.Read())
{
DateTime LastAccessed =reader.GetDateTime(1).AddMinutes(SessionExpiration);
if (LastAccessed >= DateTime.Now)
Session = Deserialize((Byte[])reader["Data"]);
}
}
finally
{
if (reader != null)
reader.Close();
if (conn != null)
conn.Close();
}
return Session;
}
private mySession Deserialize(Byte[] state)
{
if (state == null) return null;
mySession Session =
null;
Stream stream =
null;
try
{
stream =
new MemoryStream();
stream.Write(state, 0, state.Length);
stream.Position = 0;
IFormatter formatter =
new BinaryFormatter();
Session = (mySession)formatter.Deserialize(stream);
}
finally
{
if (stream != null)
stream.Close();
}
return Session;
}

At the end of the request, the Page class Unload event is fired, and an event handler registered with the Unload event will serialize the session data into binary format and save the resulting binary data into SQL Server.

private void PersistSession(Object obj, System.EventArgs arg)
{
sessionPersistence.SaveSession(Server.UrlDecode(cookie.Value).ToLower().Trim(), dsn, Session, IsNewSession);
}
public void SaveSession(string key, string dsn, mySession Session, bool IsNewSession)
{
SqlConnection conn =
new SqlConnection(dsn);
SqlCommand SaveCmd =
new SqlCommand();
SaveCmd.Connection = conn;
try
{
if (IsNewSession)
SaveCmd.CommandText = InsertStatement;
else
SaveCmd.CommandText = UpdateStatement;
SaveCmd.Parameters.Add("@ID",
new Guid(key));
SaveCmd.Parameters.Add("@Data", Serialize(Session));
SaveCmd.Parameters.Add("@LastAccessed", DateTime.Now.ToString());
conn.Open();
SaveCmd.ExecuteNonQuery();
}
finally
{
if (conn != null)
conn.Close();
}
}
private Byte[] Serialize(mySession Session)
{
if (Session == null) return null;
Stream stream =
null;
Byte[] state =
null;
try
{
IFormatter formatter =
new BinaryFormatter();
stream =
new MemoryStream();
formatter.Serialize(stream, Session);
state =
new Byte[stream.Length];
stream.Position = 0;
stream.Read(state, 0, (
int)stream.Length);
stream.Close();
}
finally
{
if (stream != null)
stream.Close();
}
return state;
}

The SessionPage class and its associated classes are packaged in the SessionUtility assembly. In a new ASP.NET project, a reference will be made to the SessionUtility assembly, and every page will derive from the SessionPage instead of from the Page class in order to share session with classic ASP codes. Once the porting is completed, the new application can switch back to use the native HttpSession object by commenting out the Session variable declaration in the SessionPage class to unhide the base HttpSession.

Storing ASP Session in Database

The ASP session can only be stored in memory,so in order to store session data in SQL Server,we need to write a COM object,In this example Visual Basic-6 object is written. instead of using the native session object. This COM object will be instantiated in the beginning of each Web request and reload the session data from SQL Server. When the ASP script is finished, this object will be terminated and the session state will be persisted back to SQL Server.

The primary purpose of the Visual Basic 6 COM Session object is to provide access to the Microsoft® Internet Information Server intrinsic objects. The Visual Basic 6.0 COM Session object uses the mySession class of SessionUtility assembly to hold the session state, and the SessionPersistence class of SessionUtility to load and save session data with SQL Server. The mySession and SessionPersistence classes are exposed as COM objects using the regasm.exe utility. The regasm.exe utility can register and create a type library for the COM client to consume Framework classes.

The session state information is reloaded during the construction of the object. The constructor (class_initialize) will first retrieve the session cookie, session timeout (SessionTimeOut), and database connection string (SessionDSN) from the Application object, and create an instance of the class mySession to hold the session data. Then the constructor will try to reload the session data from SQL Server with the given cookie. If the SQL Server does not have the session information, or the session has been expired, a new cookie will be issued. If the SQL Sever does return with the session state data, the session state will be stored in the mySession object.

Private Sub Class_Initialize()
On Error GoTo ErrHandler
Const METHOD_NAME As String = "Class_Initialize"
mySessionPersistence =
New SessionPersistence
myObjectContext = GetObjectContext()
mySessionID = ReadSessionID()
myDSNString = GetConnectionDSN()
myTimeOut = GetSessionTimeOut()
myIsNewSession =
False
Call InitContents()
Exit Sub
ErrHandler:
Err.Raise(Err.Number, METHOD_NAME & ":" & Err.Source, Err.Description)
End Sub
Private Sub InitContents()
On Error GoTo ErrHandler
Const METHOD_NAME As String = "InitContents"
If mySessionID = "" Then
myContentsEntity = New mySession
mySessionID = mySessionPersistence.GenerateKey
myIsNewSession =
True
Else
myContentsEntity = mySessionPersistence.LoadSession(mySessionID, myDSNString, myTimeOut)
End If
Exit Sub
ErrHandler:
Err.Raise(Err.Number, METHOD_NAME & ":" & Err.Source, Err.Description)
End Sub

When the object instance goes out of scope in the script, the destructor (class_terminate) will execute. The destructor will persist the session data using the SessionPersistence.SaveSession() method. If this is a new session, the destructor will also send the new cookie back to the browser.

Private Sub Class_Terminate()
On Error GoTo ErrHandler
Const METHOD_NAME As String = "Class_Terminate"
Call SetDataForSessionID()
Exit Sub
ErrHandler:
Err.Raise(Err.Number, METHOD_NAME & ":" & Err.Source, Err.Description)
End Sub
Private Sub SetDataForSessionID()
On Error GoTo ErrHandler
Const METHOD_NAME As String = "SetDataForSessionID"
Call mySessionPersistence.SaveSession(mySessionID, myDSNString, myContentsEntity, myIsNewSession)
If myIsNewSession Then Call WriteSessionID(mySessionID)
myContentsEntity =
Nothing
myObjectContext = Nothing
mySessionPersistence = Nothing
Exit Sub
ErrHandler:
Err.Raise(Err.Number, METHOD_NAME & ":" & Err.Source, Err.Description)
End Sub