Recipe 6.1 Maintaining Information Needed by All Users of an Application

     

6.1.1 Problem

You want to make certain data available to all users of an application.

6.1.2 Solution

Place the code needed to find and load the data in the Application_Start method of global.asax and store it in the Application object.

In the code-behind class for global.asax , use the .NET language of your choice to:

  1. Create an event handler for the Application_Start event.

  2. Load the application data and store it in the Application object.

The code we've written to demonstrate this solution is shown in Example 6-1 through Example 6-5. Example 6-1 and Example 6-2 show the VB and C# code-behind files for global.asax ; this code reads data from a database and places it in the Application object. Figure 6-1 shows a simple form that we've created to view the application state data. Example 6-3 shows the .aspx file that produces the form. Examples Example 6-4 and Example 6-5 show the companion VB and C# code-behind files that demonstrate how to access the application state data.

Figure 6-1. A view of some sample application state data
figs/ancb_0601.gif

6.1.3 Discussion

The purpose of the Application object is to store information once that can be simultaneously shared with all users of the application without having to access it repeatedly from a database or some other data store. A simple example is when you want to store and then share the number of times an application has been hit by all the users of the application. Another example is when you want to store and then share some common reference information, as illustrated in Figure 6-1. Using the Application object provides the ideal means to accomplish these tasks . The Application object is similar to the Session object (discussed in the next recipe), except that it stores global information as opposed to information about an individual session. The Application object is a property of the Page object that provides the ability to store virtually any data and offer access to it throughout the application by all users. Storing commonly used global data in memory can significantly improve the performance of an application.

The code we've written to illustrate this recipe provides a simple example of loading information from a database and storing it in the Application object so it can be accessed by any user on any page of an application without having to again retrieve the data from the database each time the data is needed.

Data that you want to make available throughout the application should be initialized when the application is started. The Application_Start event handler in the global.asax.vb (or global.asax.cs ) class is the best place to do this, because the Application_Start event is raised the first time the application is accessed.

In our example, the Application_Start event handler reads the titles of the chapters of this book from a database into a DataSet . We then store the table of chapter data as a smaller DataTable object in the Application object.

Because the chapter data stored in the Application object will be used for read-only data binding, the overhead of a DataSet object is not required. Therefore, a smaller DataTable object, which represents one table in a DataSet , is stored in the Application object instead.


Data stored in the Application object can be accessed from any page of an application. When you access the data, you must cast it to the correct type because all data is stored in the Application object as Objects ; without properly casting the data, your code will not compile. Our example retrieves the data and binds it to a Repeater control in the Page_Load method in Example 6-4 and Example 6-5. (Data binding is described in Chapter 1.)

To avoid " hardcoding " names of variables placed in the Application object, we recommend that you instead define public constants in the global class, as shown in Example 6-1 (VB) and Example 6-2 (C#).

Any object placed in the Application object must be free-threaded or else deadlocks, race conditions, and access violations can occur. Any object created from the classes in the Common Language Runtime is free-threaded and can be safely stored in the Application object. VB6 objects are apartment-threaded and should not be placed in the Application object.


You can update data stored in the Application object whenever your application requires it. ASP.NET is multithreaded, so many threads can access the variables within the scope of an application at the same time. Changing the variables' values in an uncontrolled fashion can cause data concurrency issues. To prevent contention between threads, the Application object must be able to block access to itself while changes are made. You can do this by calling the Lock method of the Application object, making your changes, and then calling the Unlock method, as shown here:

 
figs/vbicon.gif
  Application.Lock( )  Application.Add(APP_CHAPTER_DATA, _ ds.Tables(CHAPTER_TABLE))  Application.UnLock( )  
figs/csharpicon.gif
  Application.Lock( );  Application.Add(APP_CHAPTER_DATA, ds.Tables[CHAPTER_TABLE]);  Application.UnLock( );  

Your application should always minimize the time the Application object is locked, because all other threads are held off until the lock is released. To avoid permanent locks, ASP.NET automatically performs the unlock operation when a request is completed, a request times out, or an unhandled exception occurs and causes the request to fail.


Whenever you use the Application object in an application, be sure to consider the following points:

  • The Application object is not shared across servers in a web farm. Each server maintains its own copy of the Application object. If the values stored in the application are different on each of the servers in the web farm, your application may operate differently depending on which server was accessed.

  • Any data stored in the Application object is cleared when the application restarts. If any of that data needs to be persisted , you can place code in the Application_End event handler of global.aspx to store the data in a database or the like. Be careful in relying on the Application_End event handler to persist any important data. It is not called if the application stops abnormally, such as in a power failure or an application crash.

Example 6-1. Maintaining application state (global.asax.vb)
 Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name : Global.asax.vb ' ' Description: This module provides the code behind for the ' Global.asax page ' '***************************************************************************** Imports Microsoft.VisualBasic Imports System Imports System.Configuration Imports System.Data Imports System.Data.OleDb Namespace ASPNetCookbook.VBExamples Public Class Global Inherits System.Web.HttpApplication  'the following constant used to define the name of the variable used to   'store the chapter data in the application object   Public Const APP_CHAPTER_DATA As String = "ChapterData"  '************************************************************************* ' ' ROUTINE: Application_Start ' ' DESCRIPTION: This routine provides the event handler for the ' application start event. It is responsible for ' initializing application variables. '-------------------------------------------------------------------------  Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)   Const CHAPTER_TABLE As String = "Chapter"   Dim dbConn As OleDbConnection   Dim da As OleDbDataAdapter   Dim ds As DataSet   Dim strConnection As String   Dim strSQL As String   Try   'get the connection string from web.config and open a connection   'to the database   strConnection = _   ConfigurationSettings.AppSettings("dbConnectionString")   dbConn = New OleDbConnection(strConnection)   dbConn.Open( )   'build the query string and get the data from the database   strSQL = "SELECT ChapterNumber, Description " & _   "FROM Chapter " & _   "ORDER BY ChapterNumber"   'fill the dataset with the chapter data   da = New OleDbDataAdapter(strSQL, dbConn)   ds = New DataSet   da.Fill(ds, CHAPTER_TABLE)   'store the table containing the chapter data in the Application object   Application.Add(APP_CHAPTER_DATA, _   ds.Tables(CHAPTER_TABLE))   Finally   If (Not IsNothing(dbConn)) Then   dbConn.Close( )   End If   End Try   End Sub 'Application_Start  End Class 'Global End Namespace 

Example 6-2. Maintaining application state (global.asax.cs)
 //---------------------------------------------------------------------------- // // Module Name: Global.asax.cs // // Description: This module provides the code behind for the // Global.asax page // //**************************************************************************** using System; using System.Configuration; using System.Data; using System.Data.OleDb; namespace ASPNetCookbook.CSExamples { public class Global : System.Web.HttpApplication {  // the following constant used to define the name of the variable used to   // store the chapter data in the application object   public const String APP_CHAPTER_DATA = "ChapterData";  //************************************************************************ // // ROUTINE: Application_Start // // DESCRIPTION: This routine provides the event handler for the // application start event. It is responsible for // initializing application variables. //------------------------------------------------------------------------  protected void Application_Start(Object sender, EventArgs e)   {   const String CHAPTER_TABLE = "Chapter";   OleDbConnection dbConn = null;   OleDbDataAdapter da = null;   DataSet ds = null;   String strConnection = null;   String strSQL = null;   try   {   // get the connection string from web.config and open a connection   // to the database   strConnection =   ConfigurationSettings.AppSettings["dbConnectionString"];   dbConn = new OleDbConnection(strConnection);   dbConn.Open( );   // build the query string and get the data from the database   strSQL = "SELECT ChapterNumber, Description " +   "FROM Chapter " +   "ORDER BY ChapterNumber";   // fill the dataset with the chapter data   da = new OleDbDataAdapter(strSQL, dbConn);   ds = new DataSet( );   da.Fill(ds, CHAPTER_TABLE);   // store the table containing the chapter data in the Application object   Application.Add(APP_CHAPTER_DATA,   ds.Tables[CHAPTER_TABLE]);   } // try   finally   {   // cleanup   if (dbConn != null)   {   dbConn.Close( );   }   } // finally   } // Application_Start  } } 

Example 6-3. Using application state data (.aspx)
 <%@ Page Language="vb" AutoEventWireup="false" Codebehind="CH06ApplicationStateVB.aspx.vb" Inherits="ASPNetCookbook.VBExamples.CH06ApplicationStateVB" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Application State</title> <link rel="stylesheet" href="css/ASPNetCookbook.css"> </head> <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <form id="frmApplicationState" 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 Application State (VB) </td> </tr> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <tr> <td align="center"> <table width="500" border="0" align="center" cellpadding ="0" cellspacing="0"> <thead> <tr> <th colspan="2" class="PageHeading">Chapters in the ASP.NET Cookbook</th> </tr> </thead> <tr> <td><img src="images/spacer.gif" height="10" border="0"></td> </tr> <asp:Repeater id=repMenuItems runat ="server"> <ItemTemplate> <tr class="MenuItem"> <td align="center" width="50"> <%# DataBinder.Eval(Container.DataItem, _ "ChapterNumber") %></td> <td width="450"> <%# DataBinder.Eval(Container.DataItem, _ "Description") %></td> </tr> <tr height="2"> <td bgcolor ="#FFFFFF" colspan="2"> <img src="images/spacer.gif" border="0"></td> </tr> </ItemTemplate> </asp:Repeater> </table> </td> </tr> </table> </form> </body> </html> 

Example 6-4. Using application state data code-behind (.vb)
 Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH06ApplicationStateVB.aspx.vb ' ' Description: This module provides the code behind for the ' CH06ApplicationStateVB.aspx page ' '***************************************************************************** Imports Microsoft.VisualBasic Imports System Imports System.Data Namespace ASPNetCookbook.VBExamples Public Class CH06ApplicationStateVB Inherits System.Web.UI.Page 'controls on the form Protected repMenuItems As System.Web.UI.WebControls.Repeater '************************************************************************* ' ' 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.Load   Dim chapterData As DataTable   If (Not Page.IsPostBack( )) Then   'get the chapter data stored in the application object   chapterData = CType(Application.Item(Global.APP_CHAPTER_DATA), _   DataTable)   'bind it to the repeater to display the chapter data   repMenuItems.DataSource = chapterData   repMenuItems.DataBind( )   End If   End Sub 'Page_Load  End Class 'CH06ApplicationStateVB End Namespace 

Example 6-5. Using application state data code-behind (.cs)
 //---------------------------------------------------------------------------- // // Module Name: CH06ApplicationStateCS.ascx.cs // // Description: This module provides the code behind for // CH06ApplicationStateCS.ascx // //**************************************************************************** using System; using System.Data; using System.Web.UI.WebControls; namespace ASPNetCookbook.CSExamples { public class CH06ApplicationStateCS : System.Web.UI.Page { // controls on the form protected System.Web.UI.WebControls.Repeater repMenuItems; //************************************************************************ // // 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)   {   DataTable chapterData = null;   if (!Page.IsPostBack)   {   // get the chapter data stored in the application object   chapterData = (DataTable)(Application[Global.APP_CHAPTER_DATA]);   // bind it to the repeater to display the chapter data   repMenuItems.DataSource = chapterData;   repMenuItems.DataBind( );   }   } // Page_Load  } // CH06ApplicationStateCS } 



ASP. NET Cookbook
ASP.Net 2.0 Cookbook (Cookbooks (OReilly))
ISBN: 0596100647
EAN: 2147483647
Year: 2006
Pages: 179

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net