Friday, November 19, 2004

VJs Mega Tip Of The Day - November 19th 2004

Whidbey Days - ASP.Net 2.0 Page Life Cycle

ASP.Net 2.0 Page Life Cycle

Abstract
This article talks about the way ASP.Net 2.0 page life cycle works, it discusses the way ASP.Net page is created and displayed.

More Information
It is important for ASP.Net programmers to understand how their page is created/processed and displayed by ASP.Net framework. Sometimes many unexpected behaviors are seen in case incorrect data is accessed before or after certain page events. Below is the information on how System.Web.UI.Page methods execute. For keeping the article more users friendly and also to avoid incorrect method calls for not-recommended methods, I have discussed only those methods which I felt a user should know about.

Without further delay let us start from the html source that is written for the page. First of all the html source needs to be parsed to process the page. This is done by a method in the Page called AddParsedSubObject(). Unless you override it, this method will automatically add Literal controls to page’s control collection. This is done by first creating a control collection by calling CreateControlCollection() method.

As the child controls are parsed in the page the method AddedControl() is called which is usually triggered when a control is added to another control’s control collection. As ASP.Net pages can be viewed on various devices the method ResolveAdapter() returns the control adapter which is responsible for rendering the control on the specific device or browser requesting the ASP.Net page.

DeterminePostBackMode() is then invoked to find out what is the post back mode used for the request. If the POST method is used for postback the web form information is returned from the Context object. If the GET method is used for postback, the information from query string is returned. If the page is being requested for the first time, null is returned, many of us are used to writing code in which we check the postback property and execute specific logic, this is the method that helps the framework to get our this specific code running correctly.

More granular control on the page life cycle is available in ASP.Net 2.0. Now we have got additional events like “PreX” and “XComplete” to insert our logic before and after the usual “X” events, which we have been working with. The first such event to fire is PreInit(). This is the very beginning of page’s initialization and after the completion of this personalization information is loaded and if there is any page theme then it is initialized. I have talked more about these concepts earlier on the blog. Click Here for more information.

After the PreInit() of the page, ResolveAdapter() for individual child controls is called and then each of the control’s Init event is fired. What is interesting to note is that Init event of the child control is fired before the Init event of the page and many a times in developing complex ASP.Net applications if user plays with these events, without enough information, then unexpected behavior might resulted.

After the Init event of the control, the TrackViewState() method is triggered which will track the view state changes posted to server. It is important to know that when control’s view state data is being tracked with the state bag, page’s Init event and TrackViewState() are not yet fired. This also results into unexpected behavior in case users are writing custom controls or probably their own base page.

After the TrackViewState() of the child controls, the Init event of the page is fired. This event initializes the page and then TrackViewState() of the page is fired which tracks the changes to the page’s state bag

After the TrackViewState() for the page is called InitComplete() event is fired. This is the signal that initialization of the page and its child control is done. Though what a user should know is that ViewState for the page or the controls is not yet restored, if user tries to do anything before this data is restored the required changes in the data from the client which expected may not appear.

The view state is restored in the method LoadViewState() after whose completion ViewState data is available for a user to work on.. There is then EnsureChildControls() method which is invoked which makes sure that the page’s child controls get created.
In ASP.Net 2.0 a PreLoad() event available which would probably be the right place for user to play around with objects before the universally used load event is fired. For people who are writing base page classes and who want to perform certain tasks before standard page load event this is the right place to put their custom logic into.
After PreLoad() event, the Load() event of the page is fired. There is no need to explain what one can do with this event, isn’t it. But what should be known is that page load event is fired before the control load event unlike Init event which is fired first for the child controls and then for the page. This also many times takes custom control writers by surprise as they are expecting the control load to occur before actually the user logic on page load is executed.
So after the page Load() event, control Load() event is triggered and then the custom events like button clicks and others are fired. Many a times users want some specific functionality to be executed in their base pages, just after these postback events but also before PreRender when the pre rendering logic starts. This kind of development methodology has created issues when the derived classes call base methods before or after their custom logic when otherwise was expected. That is the place where LoadComplete() event of the page will come to use. The LoadComplete() will be called after the custom event execution for the child control is over but PreRender is not started.
After the LoadComplete() event PreRender() event of page is triggered followed by the PreRendering of each child controls. PreRender() event has always been the right place to put in the last logic before ViewState is saved. But now there is a PreRenderComplete() event which is fired after all the PreRender events of the child controls are fired, this will now be the last chance to change the data before SaveViewState() of the page is fired.
After the SaveViewState of the page; the control SaveViewState() is fired. SaveViewState() will save the changes that have happened to the data till that point and then the page will be ready to be rendered.
LoadPageStateFromPersistenceMedium() and SavePageStateToPersistenceMedium() are called before LoadViewState() and after SaveViewState() respectively. As the name indicates the ViewState is persisted so that it can be used later in the next call. I will talk in detail about how these methods work later, but as of now it is just good to know what they do.
After the SavePageStateToPersistenceMedium(), SaveStateComplete() is fired, which indicates that saving the state of the page is now complete.
After this the rendering of the page begins. First the CreateHtmlTextWriter() is fired to create the HTML text writer and then page and control Render are called. If the user wishes to change the look and feel of the way their control is rendered this is the event to do it. When the Render method completes Unload() for each child control is called and then each child control’s Dispose() is called. After disposing all the child controls, the page Unload() event is fired and then the Page’s Dispose() is called.

In case of error, the execution directly jumps to the error handling and then to unload and dispose events skipping the events in-between. This thus covers the major execution of ASP.Net page life cycle.

Below is a quick summary of the methods in their invocation order:
System.Web.UI.Page.AddParsedSubObject
System.Web.UI.Page.CreateControlCollection
System.Web.UI.Page.AddedControl
System.Web.UI.Page.ResolveAdapter
System.Web.UI.Page.DeterminePostBackMode
System.Web.UI.Page.PreInit
System.Web.UI.WebControl.ResolveAdapter
System.Web.UI.WebControl.Init
System.Web.UI.WebControl.TrackViewState
System.Web.UI.Page.Init
System.Web.UI.Page.TrackViewState
System.Web.UI.Page.InitComplete
System.Web.UI.Page.LoadPageStateFromPersistenceMedium
System.Web.UI.WebControl.LoadViewState
System.Web.UI.Page.EnsureChildControls
System.Web.UI.Page.LoadViewState
System.Web.UI.Page.PreLoad
System.Web.UI.Page.Load
System.Web.UI.WebControl.Load
System.Web.UI.WebControl.OnClick
System.Web.UI.Page.LoadComplete
System.Web.UI.Page.PreRender
System.Web.UI.WebControl.PreRender
System.Web.UI.Page.PreRenderComplete
System.Web.UI.Page.SaveViewState
System.Web.UI.WebControl.SaveViewState
System.Web.UI.Page.SaveViewState
System.Web.UI.Page.SavePageStateToPersistenceMedium
System.Web.UI.Page.SaveStateComplete
System.Web.UI.Page.CreateHtmlTextWriter
System.Web.UI.Page.Render
System.Web.UI.Page.RenderChildren
System.Web.UI.WebControl.RenderControl
System.Web.UI.Page.CreateHtmlTextWriter
System.Web.UI.WebControl.Unload
System.Web.UI.WebControl.Dispose
System.Web.UI.Page.Unload
System.Web.UI.Page.Dispose


There are many methods which I have skipped and many methods which we discussed are called multiple times on the basis of the existing conditions, I have intentionally not discussed them, though what I have tried is to make the user understand the things that happen in the background for a page to work.

So this is how a single ASP.Net page’s HTML comes on to our browser. Indeed quite a bit amount of work behind the scenes right!! I hope you will be able to unleash the potential of all these additional options available to you in Whidbey timeframe. These are some of the reasons why I am so passionate about Microsoft Technologies; they just keep getting better with every new release.

PS: The above is my understanding of the Whidbey (ASP.Net 2.0) page life cycle, if you think I have missed something or something is incorrectly mentioned then please do drop in a mail at Vishal_Joshi@MVPs.org so that I can make the necessary corrections.

PPS: Today marks the completion of second season of VJs Tip Of The Day series. I shall be back with the thrid season in new year 2005... Till then wish you best luck and a wonderful festive season...

No comments: