Wednesday, September 15, 2010

ASP.NET page's life cycle

Today I decided to discuss one of the most misconcepted features in ASP.NET; ViewState. I started to write about it, then I realized I’d better create a separate post about ASP.NET page’s life cycle. Because understanding view state depends on how accurately you know page’s life cycle. So not to mix up things, I decided to explain page’s life cycle first. Later I will refer to view state. Well, before I go on, let me explain some terms you may hear when you study in this area. One of the terms that may often be heard is IIS pipeline. According to MSDN, IIS pipeline is a state machine consisiting of the states below:

BEGIN_REQUEST
AUTHENTICATE_REQUEST
AUTHORIZE_REQUEST
RESOLVE_REQUEST_CACHE
MAP_REQUEST_HANDLER
ACQUIRE_REQUEST_STATE
PRE_EXECUTE_REQUEST_HANDLER
EXECUTE_REQUEST_HANDLER
RELEASE_REQUEST_STATE
UPDATE_REQUEST_CACHE
LOG_REQUEST
END_REQUEST


When a request is received by IIS, it goes through the state machine until it completes. In IIS 7.0, developers can register their own codes to be executed in any of these steps. This introduces another term. The codes that can be plugged into IIS pipeline to be executed, are called HTTP Modules. It means you can manipulate what happens during the execution of these steps programmatically by creating HTTP modules. At the end of the pipeline, there is another unit called HTTP Handler whose duty is to handle and retrieve the resource that has been requested in the URL by the browser. Every resource known to IIS is mapped and handled by a handler in configuration. For example, when you install ASP.NET on a machine running IIS, it will configure IIS to hand over aspx file requests to ISAPI assembly. You can create your own custom HTTP handler and configure IIS to allow your handler to handle the requests regarding a specific file type. This way you can configure your server to handle any file requests with specific extensions, even those that do not physically exist on the server, such as http://www.myserver.com/myfile.dummy.

I think I need to mention a difference between processing stages in IIS 6.0 and IIS 7.0. If a request is made in IIS 7.0 integrated mode, it goes through the same stages as in IIS 6.0. However these stages include some additional application events, such as MapRequestHandler and PostLogRequest. In fact the main difference is how ASP.NET is integrated with IIS server. In version 6.0 of IIS, there are two request processing pipelines; one for native code ISAPI filters and the other is for managed code components. In version 7.0 of IIS, ASP.NET is integrated with IIS server. This means there is one unified request processing pipeline for all requests. This is an advatnages for ASP.NET developers because, for example, they can handle requests for HTML or ASP pages and make them pass through the same authentication process as ordinary ASPX pages would.

Ok, after defining those tems, it's time to talk about the big deal. I have found dozens of web pages explaining page’s life cycle in ASP.NET on the internet. I think the one that beautifully explains what actually happens, is an image I found in MSDN:



You can see the name and the order of the methods and events that occur during the life cycle of a page. The order of occuring is top down, and from left to right. The list above is a detailed list of the events and methods. I'm going to only discuss those that are more related to view state.

1-Instantiation

Regarding page’s life cycle, the first stage is Instantiation. As you may remember, the last unit in the request processing pipeline is a HTTP handler. Every HTTP handler object has a ProcessRequest method. The life cycle of the page starts by invoking this method in the HTTP handler. It generates the page’s control hierarchy. It’s a control tree which is created by an autogenerated class that is created by ASP.NET runtime when a page is first visited after being created or being modified and saved. If you use a code behind programming model, this autogenerated class will inherit from your page’s associated class which in turn, derives from Page class. If you use inline programming model and use <script> tages directly in your page’s source, this autogenerated class will inherit from Page class. Then the class will be compiled and both the class and its compiled assembly will be saved in temporary ASP.NET folder. This will prevent redundant compilation upon each page request.
This class generates the page’s control hierarchy by parsing the page’s source, converting HTML markup of the page to Literal controls, and translating ASP.NET server controls to appropriate codes.

Let me give you an example to make it clear. Suppose you have a page with the source shown below:

<html>
<body>
    <p>Here is some text</p>
    <form id="form1" runat="server">
    <asp:Label ID="NameLabel" runat="server" Text="Name:"></asp:Label>
    <asp:TextBox runat="server" ID="NameTextBox"></asp:TextBox>
    <asp:Button ID="SendButton" runat="server" Text="Send" />
    </form>
</body>
</html>

The autogenerated class for this page could be something like this:


        LiteralControl lc1 = new LiteralControl(@"<html>\r\n<body>\r\n<p>Here is some text</p>\r\n");
        LiteralControl lc2 = new LiteralControl(@"\r\n<\body>\r\n<\html>");
       
        HtmlForm form1 = new HtmlForm();
        form1.ID = "form1";
        form1.Method = "post";

        Label l1 = new Label();
        l1.ID = "NameLabel";
        l1.Text = "Name:";

        TextBox tb1 = new TextBox();
        tb1.ID = "NameTextBox";

        Button bt1 = new Button();
        bt1.ID = "SendButton";
        bt1.Text = "Send";

        form1.Controls.Add(l1);
        form1.Controls.Add(tb1);
        form1.Controls.Add(bt1);

        Page.Controls.Add(lc1);
        Page.Controls.Add(form1);
        Page.Controls.Add(lc2);

As you can see, the properties that have been set declaratively in the page’s source, have been assigned in code too.

2-Initialization

The next stage is initialization. After the control hierarchy is built, init method occurs recursively on the controls. This method is called in bottom-up order. This means, init method of child controls happens befor init method of the container control. This makes the Page control the last one to invoke init method.
Well, so far, the control hierarchy has been created and the controls’ properties that are set declaratively, have been assigned.

3-Load View State

The next stage is Load View State. This stage occurs only when the page is posted back. At this stage, the state data that was saved in previous page visits will be loaded. Also, view state is validated at this stage.

4-Load Postback Data

The next stage is Load Postback Data. Like the previous stage, this stage occurs when the page is posted back. Load postback data happens for controls that implement IPostBackDataHandler interface. The page checks the data in form fields that have been posted back in HTTP header and finds the data related to the controls that implements IPostBackDataHandler interface and invoked the controls’ LoadPostData method. This will populate the control’s state with the posted back data.

The best example for this is the TextBox control. When you enter a string into the TextBox and post the page back, what happens is the browser requests the same page, passing the form field values (including the TextBox's new value) in HTTP headers. If you want to see the process in action, you can enable tracing on your web page with a TextBox and a Button control and enter something into the TextBox and post the page back by clicking the Button control. If you check the tracing information, in Form Collection section, you will see the new value entered into the TextBox control.

As you can see, this stage has nothing to do with view state. One of the most common misconceptions about controls and postback values is that some developers believe view state is somehow responsible for controls remembering their postback values while, in fact, these value are retrieved from form fields and are handed over to those controls that implements IPostBackDataHandler interface.

Something else worth mentioning is the two types of postback events. Controls like Button that cause postback automatically, implement IPostBackEventHandler interface. This is raised event. On the other hand, there are controls like TextBox whose value may change by the user, while they don’t raise any events after the change. These controls implements IPostBackDataHandler interface. This is changed event.

5-Load

The next stage is Load. At this stage, view state has been loaded and controls are in a consistent state.

6-Raise Postback Events

The next stage is Raise Postback Events. As I explained before, some controls implements IPostBackDataHandler interface. Their events regarding any changes in them will be invoked at this time. For example, a TextBox’s TextChanged event or a DropDownList’s SelectedIndexChanged event. Also, for those controls like Button that implement IPostBackEventHandler interface, corresponding event will fire at this stage.

7- Save View State

The next stage is Save View State. At this time of page’s life cycle, view state is constructed. It consists of the state data that must be persisted across postbacks. This is done by calling SaveViewState method of the controls in the control hierarchy. The result is serialized into base-64 encoded string. It is in the next stage where this value is persisted in a hidden form field called __VIEWSTATE.

8-Render

The next stage is Render. At this time, the actuall HTML that must be sent to the client’s browser is generated by using the control hierarchy and posted back data. This is accomplished by calling each control’s RenderControl method.

These stages are not the only stages in page’s life cycle. But regarding view state, they take a higher priority to be explained. Now that I have discussed page’s life cycle, I can explain view state in my next post. Until then, happy coding!

No comments:

Post a Comment