Application-Level Events

The Global.asax and Global.asax.cs files are added to an ASP.NET project when C#Builder generates the ASP.NET application. Their purpose is to supply entry points into the application for each request. For example, an ASP.NET application will start executing when the first request for the page is made. Some type of initialization may need to be performed at that point in time to make sure the application is ready to handle the request. Additionally, there are methods to handle different types of events that may occur during an application's lifecycle. Table 12.1 outlines what those events are by specifying the method that handles a given event and what it is for.

Table 12.1. Application Event Handlers

EVENT

PURPOSE

Application_Start

The first request to the application.

Application_End

The application is ending.

Application_BeginRequest

A request has begun.

Application_EndRequest

A request has ended.

Session_Start

A session has begun.

Session_End

A session is complete.

Application_AuthenticateRequest

User has been authenticated and their role membership can be ascertained.

Application_Error

An unhandled application error has occurred.

C#Builder creates a Global.asax file with a single Application directive, identified by the line with <%@ Application ... %>. The following line shows an Application directive tha t C#Builder creates by default. Definition of the attributes is outlined in Table 12.2.

 <%@ Application Codebehind="Global.asax.cs" Inherits="Global.Global" %> 

Table 12.2. Application Directive Attributes

NAME

PURPOSE

CodeBehind

Used by C#Builder to find the code-behind file.

Description

Text comment to describe file.

Inherits

Used by ASP.NET to find the code-behind file.

The Global.asax file appears in the designer surface as a plain white surface where components and controls can be added. This file only executes on the server and will never render a visual appearance for the client. Therefore, adding a visual control doesn't make sense because it has no effect. However, adding nonvisual components, such as data components, would be useful in situations where database interaction facilitates request processing. Chapter 15, "ADO.NET and File I/O," discusses data components in depth.

The Global.asax.cs file is the code-behind file that contains the code for application events. Each method corresponds to an entry in Table 12.1. Listing 12.1 demonstrates the sequence of event handling in Global.asax.cs. The code uses the Application state object, discussed in the next section, to build a logging system that is passed to the main Web page, which is shown in Listing 12.2. You can view this listing in C#Builder by loading the code that comes with this book.

Listing 12.1 Application Event Handling Code (Global.asax.cs)
 using System; using System.Collections; using System.ComponentModel; using System.Web; using System.Web.SessionState; namespace Global {    /// <summary>    /// Summary description for Global.    /// </summary>    public class Global : System.Web.HttpApplication    {       public const string LogName = "GlobalLog";       ArrayList globalLog = new ArrayList();       public Global()       {          InitializeComponent();          WriteAppLog("Initializing Global.asax.");       }       protected void WriteAppLog(string logEntry)       {          if (Application != null &&              Application[LogName] != null)          {             globalLog = (ArrayList)Application[LogName];          }          globalLog.Add(logEntry);          if (Application != null)          {             Application[LogName] = globalLog;          }       }       protected void Application_Start(Object sender, EventArgs e)       {          WriteAppLog("Executing Application_Start.");       }       protected void Session_Start(Object sender, EventArgs e)       {          WriteAppLog("Executing Session_Start.");       }       protected void Application_BeginRequest(Object sender, EventArgs e)       {          WriteAppLog("Executing Application_BeginRequest.");       }       protected void Application_EndRequest(Object sender, EventArgs e)       {          WriteAppLog("Executing Application_EndRequest.");       }       protected void Application_AuthenticateRequest(Object sender, EventArgs e)       {          WriteAppLog("Executing Application_AuthenticateRequest.");       }       protected void Application_Error(Object sender, EventArgs e)       {          WriteAppLog("Executing Application_Error.");       }       protected void Session_End(Object sender, EventArgs e)       {          WriteAppLog("Executing Session_End.");       }       protected void Application_End(Object sender, EventArgs e)       {          WriteAppLog("Executing Application_End.");       }       #region Web Form Designer generated code       /// <summary>       /// Required method for Designer support - do not modify       /// the contents of this method with the code editor.       /// </summary>       private void InitializeComponent()       {       }       #endregion    } } 
Listing 12.2 Web Form Displaying Application Events
 using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.Web; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace Global {    /// <summary>    /// Summary description for WebForm1.    /// </summary>    public class WebForm1 : System.Web.UI.Page    {       private void Page_Load(object sender, System.EventArgs e)       {          // Put user code to initialize the page here          ArrayList globalLog = (ArrayList)Application["GlobalLog"];          if (globalLog != null)          {             foreach (string logEntry in globalLog)             {                Response.Write(logEntry + "<br>");             }          }       }       #region Web Form Designer generated code       override protected void OnInit(EventArgs e)       {          //          // CODEGEN: This call is required by the ASP.NET Web Form Designer.          //          InitializeComponent();          base.OnInit(e);       }       /// <summary>       /// Required method for Designer support - do not modify       /// the contents of this method with the code editor.       /// </summary>       private void InitializeComponent()       {          this.Load += new System.EventHandler(this.Page_Load);       }       #endregion    } } 

The purpose of Listing 12.1 is to create a logging mechanism that captures the sequence of events throughout the application life cycle. This will help you understand when each event handler fires and offer a framework that you can experiment with for different scenarios. Although the next section explains the Application state object, the code here uses it to facilitate the logging mechanism as shown in the following line, which is an excerpt from Listing 12.1:

 protected void WriteAppLog(string logEntry) {    if (Application != null &&        Application[LogName] != null)    {       globalLog = (ArrayList)Application[LogName];    }    globalLog.Add(logEntry);    if (Application != null)    {       Application[LogName] = globalLog;    } } 

The WriteAppLog method accepts a string that is meant to be appended to a list of strings that form a logging mechanism for application events. The Application state object maintains a state bag of objects that are accessible for the life of an application. Because this method is called from the constructor, as well as other event handlers, there must be a check to see if the Application state object exists yet, which it won't if being called from the constructor. Additionally, the code must make sure that the globalLog ArrayList has been added to the Application state. Accessing it without these checks could result in a NullReferenceException being thrown. So, the logic of getting the globalLog ArrayList from Application state, adding the new string, and adding globalLog back to Application state is nicely encapsulated into this method. Now, both the constructor and event handlers can call this method with a single method call, simplifying their syntax.

Because the same Application state object is available to the entire Web application, the main Web Form accesses it to print the current log. The listing that follows is an excerpt from Listing 12.2 that shows how this is done:

 private void Page_Load(object sender, System.EventArgs e) {    // Put user code to initialize the page here    ArrayList globalLog = (ArrayList)Application["GlobalLog"];    if (globalLog != null)    {       foreach (string logEntry in globalLog)       {          Response.Write(logEntry + "<br>");       }    } } 

As shown in the preceding code, the Page_Load method pulls the ArrayList from the Application state object and iterates through the entries, printing each to the client browser. For output, the code uses the Write method of the Response object, which renders the string passed in to the client browser. Because the output is HTML, the code appends a line break tag, <br>, to the string. Figure 12.1 shows how this output appears.

Figure 12.1. Display of application events.

graphics/12fig01.gif

The output in Figure 12.1 shows the application starting up and all the steps it goes through. Each request to the page generates an Application_BeginRequest / Application_AuthenticateRequest / Application_EndRequest event sequence. There will be two of these calls because there is an extra request to establish the session. Clicking the Refresh button on the browser generates a new Application_BeginRequest / Application_AuthenticateRequest / Application_EndRequest event sequence, but not a new Session_Start. To generate a new Session_Start, close and reopen the browser. To generate a new Application_Start event, close the browser. Build the application by clicking Project, Build <project name> (Shift+F9), and reopen the browser. The rebuild causes the application to restart.

SHOP TALK
MANAGING STATE IN A STATELESS ENVIRONMENT

As you may know, the Web runs on HTTP, which is an inherently stateless transport protocol. This means that Web pages are also stateless entities and there is no built-in mechanism that allows one page on the same site to know what a previous page did. For simply displaying information, a stateless Web is fine. However, for building applications that remember users, provide personalized experiences and support e-commerce, you need a way to maintain state. ASP.NET provides state management services.

This is a huge conceptual difference from working with traditional client applications. For example, to remember the state of an application between display of one Windows Forms application and another, you just store information in fields that each form can get to. When first building Web applications, some people get caught by this before they realize how the stateless world of the Web works. In ASP.NET, they need to learn that state must be saved in special objects for application and session state. Understanding the difference will help when beginning a first Web application.



C# Builder KickStart
C# Builder KickStart
ISBN: 672325896
EAN: N/A
Year: 2003
Pages: 165

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