You want to make personalized information available to the users of your application for as long as each remains active, without having to access a database each time the information is needed and regardless of the number of pages traversed.
Create a class in which to store the personalized data, instantiate
the class and load the data, store the data object in the
Session
object, and then access the data from the
Session
object as required.
In the code-behind class for your ASP.NET pages that need access to the data, use the .NET language of your choice to:
Check to see if the object used to store the personalized data exists
in the Session
object.
If the object exists, retrieve the object from
Session
. If the object does not exist, instantiate
the class used for the personalized data and store it in the
Session
object.
Use the data as required in your application.
A simple example that illustrates this solution is shown in Examples
Example 6-6 through Example 6-10.
The example uses the class shown in Example 6-6
(CH06PersonalDataVB
for VB) and Example 6-7 (CH06PersonalDataCS
for C#)
to provide a container for some simple personalization data. This
class contains properties for each of the data items and a default
constructor.
Figure 6-2 shows a simple form that
we’ve created for viewing the current contents of
the personalization data stored in the Session
object and for entering new session state data values. Example 6-8 shows the .aspx
file that
produces the form. Example 6-9 and Example 6-10 show the companion VB and C# code-behind
files.
The approach we favor for maintaining personal information about a
user for the duration of a session—an approach that is often
referred to as personalization—is to
create a class to hold the data, instantiate and populate the object,
store the object in the Session
object, and then
access the data from the Session
object.
As its name implies, you can use the Session
object in ASP.NET to store information needed for a particular user
session. Variables stored in the Session
object
are not discarded when the user navigates between the pages of an
application. Rather, they are persisted for the entire session.
To illustrate this approach, the code-behind in our example contains
the logic needed to access the data in the Session
object. We make use of the Page_Load
method in
Example 6-9 (VB) and Example 6-10
(C#) to first check whether the Session
object
contains the personalization data. If not, we create a new
CH06PersonalDataVB
(VB) or
CH06PersonalDataCS
(C#) object using default
values, and store this new data object in the
Session
object associated with the current
session. Otherwise, we retrieve a reference to the object containing
the personalized data. Finally, we update the contents of the form by
passing the personalization object to a method that uses the data to
update the contents of the form.
In Example 6-9 and Example 6-10, a constant,
SES_PERSONALIZATION_DATA
, is used to define the
name of the variable placed in the Session
object.
This is done to avoid having to hardcode the name of the variable in
multiple locations in the code. In an application where the data is
accessed in multiple pages, the constant should be stored in
global.asax.vb
(or
global.asax.cs
) or in another class containing
global constants.
For this example, the personalization data is updated when the user
enters new personalization data values and clicks the Update button.
In the button click event handler, we check whether the data has been
stored in the Session
object, using the same code
we used in the Page_Load
method. You should always
check this condition to avoid the error that will be thrown if the
data is no longer in the Session
object. Loss of
data can occur if the session times out and ASP.NET deletes all
variables for the user session.
Next, we update the contents of the personalization object with data
from the form. In a production setting, your code will need to
perform validation on the data to ensure that it is of the correct
type, in the correct form, within the correct range, and so on.
Finally, we store the personalization data in the
Session
object and update the form contents.
This example is rather simple, but it shows the mechanics associated
with storing and retrieving data in the Session
object. In a full application, the personalization data could be read
from a database when the user logs in. If your application uses
cookies to identify a user, the Session_Start
event handler of global.asax
provides an ideal
place to retrieve the cookie that identifies the user, get the
user’s personalization data from a database, and
then place the data in the Session
object.
You can place any object in the Session
object,
but take care not to overuse the Session
object.
Large objects can significantly impact the performance of the
application by tying up system resources.
To provide the ability to associate session data with a specific
user, ASP.NET assigns a session ID to each user session. The session
ID is then used by ASP.NET to retrieve the Session
object associated with the user requesting a page.
The HTTP protocol is stateless, so some method of associating the
incoming requests with a specific user is required. By default,
ASP.NET sends a cookie containing the session ID to the client
browser as part of its response to the first page request by a user.
Subsequent page requests return the cookie data. ASP.NET retrieves
the cookie data from the request, extracts the session ID, retrieves
the Session
object for the specific user, and then
processes the requested page.
The cookie sent to the client browser is an in-memory cookie and is not persisted on the client machine. If the user closes the browser, the cookie containing the session ID is destroyed.
To support applications that do not use cookies, ASP.NET provides the
ability to automatically modify the URL to contain the session ID
(called URL munging). This method of tracking
the session ID is configured in the web.config
file and is discussed in Recipe 9.4.
ASP.NET supports three methods of storing the session information. By
default, the session data is stored in memory within the ASP.NET
process. The session data can also be stored in memory in an
out-of-process state server or SQL Server. The storage methods are
configured in the web.config
file and are
discussed in Recipe 9.4.
When using the Session
object in your application,
consider the following points:
By default, a session times out after 20 minutes of inactivity. When
a session times out, the ASP.NET process destroys all session data,
and the resources used by the session variables are recovered. The
session timeout is configured in the web.config
file and is discussed in Recipe 9.4.
If any special operations are required when a user session ends, they
can be performed in the Session_End
event handler
of global.asax
. This event is raised whenever a
session ends, whether it is done programmatically or because the
session times out. However, the Session_End
event
may not be raised if ASP.NET is terminated abruptly.
Example 6-6. Class used to store data in session object (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH06PersonalDataVB.vb ' ' Description: This module provides the container to store personalization ' data for a user ' '***************************************************************************** Namespace ASPNetCookbook.VBExamples Public Class CH06PersonalDataVB 'private attributes with default values Private mUsername As String = "" Private mResultsPerPage As Integer = 25 Private mSortBy As String = "Title" Public Property username( ) As String Get Return (mUsername) End Get Set(ByVal Value As String) mUsername = Value End Set End Property 'username Public Property resultsPerPage( ) As Integer Get Return (mResultsPerPage) End Get Set(ByVal Value As Integer) mResultsPerPage = Value End Set End Property 'resultsPerPage Public Property sortBy( ) As String Get Return (mSortBy) End Get Set(ByVal Value As String) mSortBy = Value End Set End Property 'sortBy End Class 'CH06PersonalDataVB End Namespace
Example 6-7. Class used to store data in session object (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH06PersonalDataCS // // Description: This module provides the container to store personalization // data for a user // //**************************************************************************** using System; namespace ASPNetCookbook.CSExamples { public class CH06PersonalDataCS { // private attributes with default values private String mUsername = ""; private int mResultsPerPage = 25; private String mSortBy = "Title"; public String username { get { return(mUsername); } set { mUsername = value; } } // username public int resultsPerPage { get { return(mResultsPerPage); } set { mResultsPerPage = value; } } // resultsPerPage public String sortBy { get { return(mSortBy); } set { mSortBy = value; } } // mSortBy } // CH06PersonalDataCS }
Example 6-8. Maintaining user state (.aspx)
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH06SessionStateVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH06SessionStateVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>State Session</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmSessionState" method="post" runat="server"> <table width="100%" cellpadding="0" cellspacing="0" border="0"> <tr> <td align="center"> <img src="images/ASPNETCookbookHeading_blue.gif"> </td> </tr> <tr> <td class="dividerLine"> <img src="images/spacer.gif" height="6" border="0"></td> </tr> </table> <table width="90%" align="center" border="0"> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center" class="PageHeading"> Maintaining Session State (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <table width="60%" align="center"> <tr> <td colspan="2" align="center" class="PageHeading"> Current Session Data Values</td> </tr> <tr class="MenuItem"> <td>User Name: </td> <td><asp:Label ID="labUserName" Runat="server" /></td> </tr> <tr class="MenuItem"> <td>Results Per Page: </td> <td><asp:Label ID="labResultsPerPage" Runat="server" /></td> </tr> <tr class="MenuItem"> <td>Sort By: </td> <td><asp:Label ID="labSortBy" Runat="server" /></td> </tr> </table> <br /> <table width="60%" align="center"> <tr> <td colspan="2" align="center" class="PageHeading"> Enter New Session Data Values</td> </tr> <tr class="MenuItem"> <td>User Name: </td> <td><asp:TextBox ID="txtUserName" Runat="server" /></td> </tr> <tr class="MenuItem"> <td>Results Per Page: </td> <td><asp:TextBox ID="txtResultsPerPage" Runat="server" /></td> </tr> <tr class="MenuItem"> <td>Sort By: </td> <td><asp:TextBox ID="txtSortBy" Runat="server" /></td> </tr> <tr> <td colspan="2" align="center"> <br /> <asp:ImageButton ID="btnUpdate" Runat="server" ImageUrl="images/buttons/button_update.gif" /> </td> </tr> </table> </td> </tr> </table> </form> </body> </html>
Example 6-9. Maintaining user state (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH06SessionStateVB.aspx.vb ' ' Description: This module provides the code behind for ' CH06SessionStateVB.aspx ' '***************************************************************************** Imports Microsoft.VisualBasic Namespace ASPNetCookbook.VBExamples Public Class CH06SessionStateVB Inherits System.Web.UI.Page 'controls on the form Protected labUserName As System.Web.UI.WebControls.Label Protected labResultsPerPage As System.Web.UI.WebControls.Label Protected labSortBy As System.Web.UI.WebControls.Label Protected txtUserName As System.Web.UI.WebControls.TextBox Protected txtResultsPerPage As System.Web.UI.WebControls.TextBox Protected txtSortBy As System.Web.UI.WebControls.TextBox Protected WithEvents btnUpdate As System.Web.UI.WebControls.ImageButton'The following constant defines the name of the session variable used
'to store the user personalization data
Public SES_PERSONALIZATION_DATA As String = "PersonalizationData"
'************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for initializing the controls ' on the page. '------------------------------------------------------------------------- Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.LoadDim personalData As CH06PersonalDataVB
If (Not Page.IsPostBack( )) Then
'check to see if the session data exists
If (IsNothing(Session(SES_PERSONALIZATION_DATA))) Then
'data does not exist in session so create a new personalization
'object and place it in session scope
personalData = New CH06PersonalDataVB
Session.Add(SES_PERSONALIZATION_DATA, _
personalData)
Else
'data exists in session so get a reference to the data
personalData = CType(Session(SES_PERSONALIZATION_DATA), _
CH06PersonalDataVB)
End If
'update contents on the form
updateFormData(personalData)
End If
End Sub 'Page_Load '************************************************************************* ' ' ROUTINE: btnUpdate_Click ' ' DESCRIPTION: This routine provides the event handler for the update ' button click event. It is responsible for updating the ' contents of the session variable used to store the ' personalization data and updating the form. '-------------------------------------------------------------------------Private Sub btnUpdate_Click(ByVal sender As Object, _
ByVal e As System.Web.UI.ImageClickEventArgs) _
Handles btnUpdate.Click
Dim personalData As CH06PersonalDataVB
'check to see if the session data exists
If (IsNothing(Session(SES_PERSONALIZATION_DATA))) Then
'data does not exist in session so create a new personalization object
personalData = New CH06PersonalDataVB
Else
'data exists in session so get a reference to the data
personalData = CType(Session(SES_PERSONALIZATION_DATA), _
CH06PersonalDataVB)
End If
'update contents of session object from form
personalData.username = txtUserName.Text
personalData.resultsPerPage = CInt(txtResultsPerPage.Text)
personalData.sortBy = txtSortBy.Text
'update contents of session object
Session(SES_PERSONALIZATION_DATA) = personalData
'update contents on the form
updateFormData(personalData)
End Sub 'btnUpdate_Click
'************************************************************************* ' ' ROUTINE: updateFormData ' ' DESCRIPTION: This routine updates the contents of the form from the ' passed data. '------------------------------------------------------------------------- Private Sub updateFormData(ByVal personalData As CH06PersonalDataVB) labUserName.Text = personalData.username labResultsPerPage.Text = personalData.resultsPerPage.ToString( ) labSortBy.Text = personalData.sortBy End Sub 'updateFormData End Class 'CH06SessionStateVB End Namespace
Example 6-10. Maintaining user state (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH06SessionStateCS.ascx.cs // // Description: This module provides the code behind for // CH06SessionStateCS.ascx // //**************************************************************************** using System; using System.Web.UI; using System.Web.UI.WebControls; namespace ASPNetCookbook.CSExamples { public class CH06SessionStateCS : System.Web.UI.Page { // controls on the form protected System.Web.UI.WebControls.Label labUserName; protected System.Web.UI.WebControls.Label labResultsPerPage; protected System.Web.UI.WebControls.Label labSortBy; protected System.Web.UI.WebControls.TextBox txtUserName; protected System.Web.UI.WebControls.TextBox txtResultsPerPage; protected System.Web.UI.WebControls.TextBox txtSortBy; protected System.Web.UI.WebControls.ImageButton btnUpdate;// The following constant defines the name of the session variable used
// to store the user personalization data
public String SES_PERSONALIZATION_DATA = "PersonalizationData";
//************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. //------------------------------------------------------------------------ private void Page_Load(object sender, System.EventArgs e) {CH06PersonalDataCS personalData = null;
// wire the update button click event
this.btnUpdate.Click +=
new ImageClickEventHandler(this.btnUpdate_Click);
if (!Page.IsPostBack)
{
// check to see if the session data exists
if (Session[SES_PERSONALIZATION_DATA] == null)
{
// data does not exist in session so create a new personalization
// object and place it in session scope
personalData = new CH06PersonalDataCS( );
Session.Add(SES_PERSONALIZATION_DATA,
personalData);
}
else
{
// data exists in session so get a reference to the data
personalData = (CH06PersonalDataCS)
(Session[SES_PERSONALIZATION_DATA]);
}
// update contents on the form
updateFormData(personalData);
}
} // Page_Load //************************************************************************ // // ROUTINE: btnUpdate_Click // // DESCRIPTION: This routine provides the event handler for the update // button click event. It is responsible for updating the // contents of the session variable used to store the // personalization data and updating the form. //------------------------------------------------------------------------private void btnUpdate_Click(Object sender,
System.Web.UI.ImageClickEventArgs e)
{
CH06PersonalDataCS personalData = null;
//check to see if the session data exists
if (Session[SES_PERSONALIZATION_DATA] == null)
{
// data does not exist in session so create a new
// personalization object
personalData = new CH06PersonalDataCS( );
}
else
{
//data exists in session so get a reference to the data
personalData = (CH06PersonalDataCS)(Session[SES_PERSONALIZATION_DATA]);
}
// update contents of session object from form
personalData.username = txtUserName.Text;
personalData.resultsPerPage = Convert.ToInt32(txtResultsPerPage.Text);
personalData.sortBy = txtSortBy.Text;
//update contents of session object
Session[SES_PERSONALIZATION_DATA] = personalData;
// update contents on the form
updateFormData(personalData);
} // btnUpdate_Click
//************************************************************************ // // ROUTINE: updateFormData // // DESCRIPTION: This routine updates the contents of the form from the // passed data. //------------------------------------------------------------------------ private void updateFormData(CH06PersonalDataCS personalData) { labUserName.Text = personalData.username; labResultsPerPage.Text = personalData.resultsPerPage.ToString( ); labSortBy.Text = personalData.sortBy; } // updateFormData } // CH06SessionStateCS }