Control Life CycleThe examples so far have demonstrated the use of server-side events to coordinate the activities of an ASP.NET application as part of an .aspx page. Each HTTP request / response cycle that the page executes follows a well-defined process known as the control execution life cycle. The Page server control orchestrates these activities on behalf of all the server controls in the Page's control tree. Control developers need to understand the flow of execution to ensure that their custom controls perform as expected as part of an ASP.NET Web Form. Figure 5-21 provides a high-level view of the page life cycle process.Figure 5-21. An overview of the page life cycleAfter the initial page request as an HTTP GET, each subsequent HTTP POST page request/response cycle generally consists of the following steps:
This process is what provides the illusion of a stateful application to the end user. During each request/response round-trip, state is unpacked, changes are processed, the UI is updated, and the page is sent back to the user's browser with its new state values embedded in a hidden form field as ViewState, ready for the next request/response cycle. We next examine what events are available to controls as the page life cycle executes on the server side.Plugging Into the Life CycleServer controls have a well-defined behavior pattern that coincides with the overall page life cycle. The ASP.NET framework provides a series of events that server controls can override to customize behavior during each phase of the life cycle. Table 5-1 provides an overview of each of these events.Table 5-1. Server Control Events Related to the Control Execution Life Cycle
As you can see in Table 5-1, ASP.NET provides each server control the capability to finely tune each phase in the life cycle. You can choose to accept default behavior, or you can customize a particular phase by overriding the appropriate event.The Lifecycle Server ControlNow that we have covered the basics of the control execution life cycle, we are going to examine this process in more detail by overriding all available events in a server control named Lifecycle. The overridden methods fall into two camps: those that raise defined events exposed by a control and those that are not events but perform a necessary action for the control.OnInit, OnLoad, OnPreRender, and OnUnload are events defined in System.Web.UI.Control that a control developer can override as required for a particular control. LoadViewState, LoadPostData, RaisePostDataChangedEvent, RaisePostBackEvent, TrackViewState, SaveViewState, and Render are all events that perform necessary actions for the control to maintain its state and event processing.CAUTION As with most object-oriented class hierarchies, it is usually (though not always) necessary to call the base class's version of an overridden method in the descendent class to ensure consistent behavior. If the base method is not called in the descendent class, instances of that class will most likely fail to behave as expected-or worse, they could cause instability.The implementation of Dispose deviates from the previous description for overridden methods. The Control class does expose a Dispose event, but it does not have an OnDispose method to raise it. Instead, providing a Dispose method follows the design pattern for objects that work with scarce resources, implementing the IDisposable interface.Life Cycle and the HTTP Protocols GET and POSTThe page life cycle differs based on whether the Web Form is requested for the first time via an HTTP GET or instead is initiated as part of a postback resulting from an HTTP POST generated by a control element on the page submitting the Web Form back to the server. The HTTP POST generally causes more life cycle activities because of the requirement to process data posted by the client back to the web server, raising events associated with state changes.Figure 5-22 shows the two variants (initial GET versus POST) of the Web Form life cycle and the names of the phases we discuss in detail shortly.Figure 5-22. The control life cycleIn order to discuss the control life cycle, we use a control that overrides the methods necessary to track the execution of each of the life cycle events as they occur. Listing 5-19 provides the class file for the Lifecycle control that handles this task. The implementation of each overridden method is quite simple, with a call to the trace function notifying us that the method is executing.Listing 5-19. The Lifecycle Control Class Fileusing System;using System.Web.UI;using System.Collections.Specialized;using System.Diagnostics;namespace ControlsBookLib.Ch05{ [ToolboxData("<{0}:Lifecycle runat=server></{0}:Lifecycle>")] public class Lifecycle : Control, IPostBackEventHandler, IPostBackDataHandler { // Init Event override protected void OnInit(System.EventArgs e) { Trace("Lifecycle: Init Event."); base.OnInit(e); } override protected void TrackViewState() { Trace("Lifecycle: Track ViewState."); base.TrackViewState(); } // Load ViewState Event override protected void LoadViewState(object savedState) { Trace("Lifecycle: Load ViewState Event."); base.LoadViewState(savedState); } // Load Postback Data Event public bool LoadPostData(string postDataKey, NameValueCollection postCollection) { Trace("Lifecycle: Load PostBack Data Event."); Page.RegisterRequiresRaiseEvent(this); return true; } // Load Event override protected void OnLoad(System.EventArgs e) { Trace("Lifecycle: Load Event."); base.OnLoad(e); } // Post Data Changed Event public void RaisePostDataChangedEvent() { Trace("Lifecycle: Post Data Changed Event."); } // Postback Event public void RaisePostBackEvent(string argument) { Trace("Lifecycle: PostBack Event."); } // PreRender Event override protected void OnPreRender(System.EventArgs e) { Trace("Lifecycle: PreRender Event."); Page.RegisterRequiresPostBack(this); base.OnPreRender(e); } // Save ViewState override protected object SaveViewState() { Trace("Lifecycle: Save ViewState."); return base.SaveViewState(); } // Render Event override protected void Render(HtmlTextWriter writer) { base.Render(writer); Trace("Lifecycle: Render Event."); writer.Write("<h3>LifeCycle Control</h3>"); } // Unload Event override protected void OnUnload(System.EventArgs e) { Trace("Lifecycle: Unload Event."); base.OnUnload(e); } // Dispose Event public override void Dispose() { Trace("Lifecycle: Dispose Event."); base.Dispose(); } private void Trace(string info) { Context.Trace.Warn(info); Debug.WriteLine(info); } }}Listings 5-20 and 5-21 outline the Web Form that hosts the control, with the ASP.NET tracing mechanism turned on. The UI appearance is a single button on the Web Form with trace output turned on.Listing 5-20. The Life Cycle Web Form .aspx Page File<%@ Register TagPrefix="apressUC" TagName="ControlsBookFooter"Src="..\ControlsBookFooter.ascx" %><%@ Register TagPrefix="apressUC" TagName="ControlsBookHeader"Src="..\ControlsBookHeader.ascx" %><%@ Register TagPrefix="apress" Namespace="ControlsBookLib.Ch05"Assembly="ControlsBookLib" %><%@ Page Trace="true" language="c#" Codebehind="LifeCycle.aspx.cs"AutoEventWireup="false" Inherits="ControlsBookWeb.Ch05.LifeCycle" %><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" ><HTML><HEAD><title>Ch05 Lifecycle</title><meta name="GENERATOR" Content="Microsoft Visual Studio 7.0"><meta name="CODE_LANGUAGE" Content="C#"><meta name="vs_defaultClientScript" content="JavaScript"><meta name="vs_targetSchema"content="http://schemas.microsoft.com/intellisense/ie5"></HEAD><body MS_POSITIONING="FlowLayout"><form id="LifeCycle" method="post" runat="server"><apressUC:ControlsBookHeader id="Header" runat="server" ChapterNumber="5"ChapterTitle="Event-based Programming" /><h3>Ch05 Lifecycle</h3><apress:Lifecycle id="life1" runat="server" /><asp:Button id="Button1" runat="server" Text="Button"></asp:Button><apressUC:ControlsBookFooter id="Footer" runat="server" /></form></body></HTML>Listing 5-21. The Life Cycle Web Form Code-Behind Class Fileusing System;using System.Web;using System.Web.SessionState;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.HtmlControls;namespace ControlsBookWeb.Ch05{ public class LifeCycle : System.Web.UI.Page { protected System.Web.UI.WebControls.Button Button1; protected ControlsBookLib.Ch05.Lifecycle life1; private void Page_Load(object sender, System.EventArgs e) { } #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 first execution of the Life Cycle Web Form results in an HTTP GET protocol request and generates the life cycle events shown in the ASP.NET Trace output of Figure 5-23.Figure 5-23. The Lifecycle.aspx trace output from an HTTP GET requestWe next cover the life cycle events that occur when an HTTP GET request occurs, starting with the Init event.