A page instance is created on every request from the client, and its execution causes itself and its contained controls to iterate through their life-cycle stages. Page execution begins when the HTTP runtime invokes
ProcessRequest
, which kicks off the page and control life cycles. The life cycle consists of a sequence of stages and steps. Some of these stages can be controlled through
The page life cycle is
When the HTTP runtime instantiates the page class to serve the current request, the page constructor builds a tree of controls. The tree of controls ties into the actual class that the page parser created after looking at the ASPX source. It is important to note that when the request processing begins, all child controls and page
The very first step in the page lifetime is determining why the runtime is processing the page request. There are various possible reasons: a normal request, postback, cross-page postback, or callback. The page object configures its internal state based on the actual reason, and it prepares the collection of posted values (if any) based on the method of the request—either GET or POST . After this first step, the page is ready to fire events to the user code.
Introduced with ASP.NET 2.0, this event is the entry point in the page life cycle. When the event fires, no master page and no theme have been associated with the page. Furthermore, the page scroll position has been restored, posted data is available, and all page controls have been
The master page, if one exists, and the theme have been set and can't be changed anymore. The page processor—that is, the ProcessRequest method on the Page class—proceeds and iterates over all child controls to give them a chance to initialize their state in a context-sensitive way. All child controls have their OnInit method invoked recursively. For each control in the control collection, the naming container and a specific ID are set, if not assigned in the source.
The
Init
event
Introduced with ASP.NET 2.0, this page-only event signals the end of the initialization substage. For a page, only one operation takes place in between the Init and InitComplete events: tracking of view-state changes is turned on. Tracking view state is the operation that ultimately enables controls to really persist in the storage medium any values that are programmatically added to the ViewState collection. Simply put, for controls not tracking their view state, any values added to their ViewState are lost across postbacks.
All controls
| Important |
In light of the previous statement, note that any value written to the
ViewState
collection before
InitComplete
won't be available on the
|
If the page is being
At this stage, each control is given a chance to update its current state to make it identical to what it was on last request. There's no event to wire up to handle the view-state restoration. If something needs be customized here, you have to resort to overriding the LoadViewState method, defined as protected and virtual on the Control class.
All the client data packed in the HTTP request—that is, the contents of all input fields defined with the <form> tag—are processed at this time. Posted data usually take the following form:
TextBox1=text&DropDownList1=selectedItem&Button1=Submit
It's an &-separated string of
If a posted name doesn't match any server controls, it is left over and temporarily parked in a separate collection, ready for a second try later.
Introduced with ASP.NET 2.0, the
PreLoad
event merely indicates that the page has
The
Load
event is raised for the page first and then recursively for all child controls. At this time, controls in the page tree are created and their state fully reflects both the previous state and any data posted from the client. The page is ready to execute any initialization code that has to do with the logic and behavior of the page. At this time, access to control properties and view state is
When all controls in the page have been given a chance to complete their initialization before display, the page processor makes a second try on posted values that haven't been matched to existing controls. The behavior described earlier in the "Processing Posted Data" section is repeated on the name/value pairs that were left over previously. This apparently weird approach addresses a specific scenario—the use of dynamically created controls.
Imagine adding a control to the page tree dynamically—for example, in response to a certain user action. As mentioned, the page is rebuilt from scratch after each postback, so any information about the dynamically created control is lost. On the other hand, when the page's form is submitted, the dynamic control there is filled with legal and valid information that is regularly posted. By design, there can't be any server control to match the ID of the dynamic control the first time posted data is processed. However, the ASP.NET framework recognizes that some controls could be created in the Load event. For this reason, it makes sense to give it a second try to see whether a match is possible after the user code has run for a while.
If the dynamic control has been re-created in the Load event, a match is now possible and the control can refresh its state with posted data.
The postback mechanism is the heart of ASP.NET programming. It consists of posting form data to the same page using the view state to restore the call context—that is, the same state of controls existing when the posting page was last generated on the server.
After the page has been
The whole ASP.NET machinery works around an implicit assumption: there must be a one-toone correspondence between some HTML input tags that
For all controls that had the LoadPostData method return true , it's now time to execute the second method of the IPostBackDataHandler interface: the RaisePostDataChangedEvent method. The method signals the control to notify the ASP.NET application that the state of the control has changed. The implementation of the method is up to each control. However, most controls do the same thing: raise a server event and give page authors a way to kick in and execute code to handle the situation. For example, if the Text property of a TextBox changes over a postback, the TextBox raises the TextChanged event to the host page.
Any page postback starts with some client action that intends to trigger a server-side action. For example, clicking a client button posts the current contents of the displayed form to the server, thus requiring some action and a new, refreshed page output. The client button control—typically, a hyperlink or a submit button—is associated with a server control that implements the IPostBackEventHandler interface.
The page processor looks at the posted data and determines the control that caused the postback. If this control implements the IPostBackEventHandler interface, the processor invokes the RaisePostBackEvent method. The implementation of this method is left to the control and can vary quite a bit, at least in theory. In practice, though, any posting control raises a server event letting page authors write code in response to the postback. For example, the Button control raises the onclick event.
There are two ways a page can post back to the server—by using a submit button (that is, <input type="submit">) or through script. The markup for a submit button is generated through the Button server control. Instead of using LinkButton controls and other controls, insert some script code in the client page to bind an HTML event (for example, onclick ) to the form's submit method in the browser's HTML object model. We'll return to this topic in the next chapter.
| Note |
In ASP.NET 2.0, a new property,
UseSubmitBehavior
, exists on the
Button
class to let page developers control the client behavior of the corresponding HTML element as far as form submission is
|
Introduced in ASP.NET 2.0, the page-only LoadComplete event signals the end of the pagepreparation phase. It is important to note that no child controls will ever receive this event. After firing LoadComplete , the page enters its rendering stage.
After handling the postback event, the page is ready for generating the output for the browser. The rendering stage is divided in two parts—prerendering and markup generation. The prerendering substage is in turn characterized by two events for preprocessing and postprocessing.
By handling this event, pages and controls can perform any updates before the output is rendered. The
PreRender
event fires for the page first and then recursively for all controls. Note that at this time the page ensures that all child controls are created. This step is important
Because the
PreRender
event is recursively
The next step before each control is rendered out to generate the markup for the page is saving the current state of the page to the view-state storage medium. It is important to note that every action taken after this point that modifies the state could affect the rendering, but it is not persisted and won't be retrieved on the next postback. Saving the page state is a recursive process in which the page processor walks its way through the whole page tree calling the
SaveViewState
method on constituent controls and the page itself.
SaveViewState
is a protected and virtual (that is, overridable) method that is responsible for
In ASP.NET 2.0, controls provide a second type of state, known as a "control state." A control state is a sort of private view state that is not subject to the application's control. In other words, the control state of a control can't be programmatically disabled as is the case with the view state. The control state is persisted at this time, too.
Introduced with ASP.NET 2.0, the SaveStateComplete event occurs when the state of controls on the page have been completely saved to the persistence medium.
| Note |
The view state of the page and all individual controls is
|
The generation of the markup for the browser is obtained by calling each constituent control to render its own markup, which will be accumulated into a buffer. Several overridable methods allow control developers to intervene in various steps during the markup generation—begin tag, body, and end tag. No user event is associated with the rendering phase.
The rendering phase is followed by a recursive call that raises the Unload event for each control, and finally for the page itself. The Unload event exists to perform any final cleanup before the page object is released. Typical operations are closing files and database connections.
Note that the unload notification arrives when the page or the control is being unloaded but has not been disposed of yet. Overriding the
Dispose
method of the
Page
class, or more simply handling the page's
Disposed
event, provides the last possibility for the actual page to perform final clean up before it is released from memory. The page processor