Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 74 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
74
Dung lượng
411,51 KB
Nội dung
Asynchronous Partial Page Rendering: Server Side Processing The previous chapter followed the current client-side PageRequestManager instance as it made an asynchronous page postback or partial-page-rendering request to the server. This chapter will move on to the server side to follow the asynchronous page postback request from the time it arrives in ASP.NET to the time the final response text is sent back to the server. Chapter 21 followed the Page object as it went through its life cycle phases to process the first request made to a Web page enabled for partial page rendering. Since the first request wasn’t a postback, the Page object skipped the postback-related life cycle phases when it was processing the first request. This chapter, on the other hand, follows the current Page object as it goes through its life cycle phases to process an asynchronous page postback request to the same page that the first request downloaded. Since an asynchronous page postback is a postback request, the current Page will go through both postback and non-postback life cycle phases, shown in Listing 21-1 and Figure 21-2 . Since the non-postback life cycle phases were discussed thoroughly in Chapter 21 , I’ll discuss only the postback-related life cycle phases in this chapter. RetrievePostData This is the life cycle phase in which the Page object populates an internal collection of type NameValueCollection named _requestValueCollection with the posted data, as shown in Listing 23-1 . As such, this phase makes sense for postback requests — whether synchronous or asynchronous. c23.indd 1105c23.indd 1105 8/20/07 8:41:21 PM8/20/07 8:41:21 PM Chapter 23: Asynchronous Partial Page Rendering 1106 Listing 23-1: The RetrievePostData Method of the Page Object private void RetrievePostData() { if (this._request.HttpVerb == HttpVerb.POST && this._request.HasForm) this._requestValueCollection = this._request.Form; else if (this._request.HasQueryString) this._requestValueCollection = this._request.QueryString; } Depending on the HTTP verb used to make a request, the clients of a page will use one of the following two approaches to submit data to the server. If the HTTP POST verb is used to make a request, the clients of the page include the data in the body of the request. The data consists of a list of data items separated by the & character, each of which consists of two parts separated by the equals sign ( = ). The first part of each data item helps the server determine what type of information the item contains. The second part of each data item contains the actual data or information being submitted. As an example, consider the ASP.NET page shown in Listing 23-2 . As you can see, this page contains a TextBox and a DropDownList server control. Every ASP.NET server control inherits a property named UniqueID from the Control base class. The value of this property is automatically set by ASP.NET when the page containing the server control is accessed. This value is a string that contains one or more substrings separated by the dollar sign, of which the first substring contains the value of the ID property of the control and the subsequent sub- strings contain the values of the UniqueID properties of those parent controls of the control that imple- ment the INamingContainer interface. In the case of Listing 23-2 , none of the parent controls of the TextBox and DropDownList server controls (other than the Page itself whose UniqueID property returns an empty string) implements this interface, which means that ASP.NET sets the values of the UniqueID properties of these two server controls to the respective values of their ID properties. You may be wondering what the significance of the UniqueID property of a server control is. As the name suggests, this property uniquely identifies the server control among other server controls on the current page. Listing 23-2: A Page that Contains a TextBox and a DropDownList Server Control <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml”> <head runat=”server”> <title>Untitled Page</title> </head> <body> <form id=”form1” runat=”server”> <asp:TextBox runat=”server” ID=”TextBox1” /> <asp:DropDownList runat=”server” ID=”DropDownList1”> <asp:ListItem Text=”Text1” Value=”Value1” /> <asp:ListItem Text=”Text2” Value=”Value2” /> <asp:ListItem Text=”Text3” Value=”Value3” /> </asp:DropDownList> c23.indd 1106c23.indd 1106 8/20/07 8:41:22 PM8/20/07 8:41:22 PM Chapter 23: Asynchronous Partial Page Rendering 1107 <asp:Button runat=”server” Text=”Submit” /> </form> </body> </html> When the browser accesses this page, it receives the HTML markup text shown in Listing 23-3 . Each server control renders the value of its UnqiueID property as the value of the name attribute of the HTML element that represents the control. Therefore, the TextBox and DropDownList server controls render the values of their UniqueID properties as the values of the name attributes of the input and select HTML elements, respectively, as shown in the boldface portions of the following code listing: <input name=”TextBox1” type=”text” id=”TextBox1” /> <select name=”DropDownList1” id=”DropDownList1”> <option value=”Value1”>Text1</option> <option value=”Value2”>Text2</option> <option value=”Value3”>Text3</option> </select> Listing 23-3: The HTML Markup Text Sent to the Client <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml”> <head> <title>Untitled Page </title> </head> <body> <form name=”form1” method=”post” action=”Default7.aspx” id=”form2”> <div> <input type=”hidden” name=”__VIEWSTATE” id=”__VIEWSTATE” value=”/wEPDwUKMTAxNzk2MjY2OWRkxj+0HeO0c5N0xVutp03x6OdaSpw=” /> </div> <input name=”TextBox1” type=”text” id=”TextBox1” /> <select name=”DropDownList1” id=”DropDownList1”> <option value=”Value1”>Text1</option> <option value=”Value2”>Text2</option> <option value=”Value3”>Text3</option> </select> <input type=”submit” name=”ctl02” value=”Submit” /> </form> </body> </html> Now imagine that the end user enters the string MyText into the text field, selects the Text2 option from the select element, and clicks the Submit button. The browser retrieves the following information: ❑ The value of the name HTML attribute of the text field — that is, the string “TextBox1” . Recall that this value is the value of the UniqueID property of the TextBox server control. ❑ The value of the name HTML attribute of the select HTML element — that is, the string “DropDownList1” . Recall that this value is that of the UniqueID property of the DropDownList server control. c23.indd 1107c23.indd 1107 8/20/07 8:41:22 PM8/20/07 8:41:22 PM Chapter 23: Asynchronous Partial Page Rendering 1108 ❑ The string that the end user has entered into the text field — that is, the string MyText . ❑ The value of the value HTML attribute of the selected option of the select HTML element — that is, the string “Value2” . Therefore, the data that the browser needs to send to the server consists of two data items. The first con- tains the string that the end user has entered into the text field, and the second contains the value of the value HTML attribute of the selected option of the select HTML element: TextBox1=MyText&DropDownList1=Value2 As you can see, each data item consists of two parts. The first part is the value of the UniqueID property of the server control and the second part is the value associated with the server control. The UniqueID property values allow ASP.NET to determine which data item is associated with which server control. So far, I’ve covered the case in which the client uses the HTTP POST verb to make its request to the server. The second scenario is when the client uses the HTTP GET verb. This scenario often involves e-commerce Web applications. For example, consider a page that displays the list of product names to the end users. When a user selects a product to see more details about it, the primary key values of the product and its distributor are passed as a query string to the server: http://www.mysite.com/Product.aspx?ProductID=2&DistributorID=3 As you can see, the query string consists of a list of data items separated by the ampersand character, each of which consists of two parts separated by the equals sign. ASP.NET represents each request with an instance of a class named HttpReques t, which exposes two collection properties of type NameValueCollection named Form and QueryString . ASP.NET auto- matically populates the Form collection with the posted data if the request was made using the HTTP POST verb; otherwise it populates the QueryString collection with the posted data. Keep in mind that we’re following the current Page through its life cycle phases to process the asynchro- nous page postback method that the current client-side PageRequestManager instance has made to the server. As we just discussed, the clients of a page have two options when it comes to submitting data to the server. Which option did the current client-side PageRequestManager instance use to submit its data to the server? The answer lies in Listing 22-22 . Recall that this code listing presents the internal implementation of the _onFormSubmit method of the current client-side PageRequestManager instance. As we discussed in the previous chapter, this method is automatically invoked when a page postback occurs, allowing the current client-side PageRequestManager instance to intercept the page postback before the page is actually posted back to the server. The current client-side PageRequestManager instance then determines whether the page must be posted back asynchronously. If so, it takes over the form submission, bypassing the browser’s default synchronous form submission. As Listing 22-22 shows, the current client-side PageRequestManager instance iterates through all the input form elements on the current page, generates for each input form element one string that consists of two substrings separated by the equals sign (the first substring containing the value of the name HTML attribute of the form element and the second containing the value of the form element), and finally packs all these strings into a single string using the & character as the separator. Recall from Listing 22-22 that the current client-side PageRequestManager instance adds this string to the body of c23.indd 1108c23.indd 1108 8/20/07 8:41:22 PM8/20/07 8:41:22 PM Chapter 23: Asynchronous Partial Page Rendering 1109 the request being made to the server. As you can see, the current client-side PageRequestManager instance submits its data to the server via the body of an HTTP POST request. Now back to the implementation of the RetrievePostData method of the Page object, as shown in Listing 23-1 . Recall that the Page object calls this method when it enters the Retrieve Post Data life cycle phase. As this code listing shows, this method simply stores the content of the Form or QueryString collection of the HttpRequest object that represents the current request in an internal collection named _requestValueCollection . This collection contains one name/value pair for each posted data item. Recall that each posted data item consists of two parts separated by the equals sign. The name part of each name/value pair in this collection contains the first part of the data item and the value part contains the second part of the data item. This means that the first part of the data item can be used as an index into the collection to access the second part of the data item. For example, in the case of the examples dis- cussed earlier, the following items are true: ❑ The UniqueID property value of the TextBox server control can be used as an index into the _requestValueCollection to access the text that the end user has entered into the text field: string text1 = this._requestValueCollection[“TextBox1”]; ❑ The UniqueID property value of the DropDownList server control can be used as an index into the _requestValueCollection to access the value of the value HTML attribute of the selected option of the select HTML element associated with the server control: string text1 = this._requestValueCollection[“DropDownList1”]; ❑ The string “ProductID” can be used as an index into the _requestValueCollection to access the primary key value of the product: string text1 = this._requestValueCollection[“ProductID”]; ❑ The string “DistributorID” can be used as an index into the _requestValueCollection to access the primary key value of the distributor: string text1 = this._requestValueCollection[“DistributorID”]; Since the current Page is processing the asynchronous request shown in Listing 22-22 , the _requestValueCollection of the current Page contains all the name/value pairs that Listing 22-22 stuffed into the body of the request. LoadScrollPosition This is the life cycle phase in which the Page object retrieves the scroll x and y positions from the _requestValueCollection and assigns them to the _scrollPositionX and _scrollPositionY fields, respectively, as shown in Listing 23-4 . As you’ll see later, the Page object uses these two fields to set the scroll position in the response text before submitting the response back to the client. This life cycle phase takes effect only if the MaintainScrollPositionOnPostBack property of the Page object has been set to true . As the name suggests, this property instructs the Page to maintain the scroll position on page postbacks — be they synchronous or asynchronous. c23.indd 1109c23.indd 1109 8/20/07 8:41:23 PM8/20/07 8:41:23 PM Chapter 23: Asynchronous Partial Page Rendering 1110 Listing 23-4: The LoadScrollPosition Method of the Page Object Private void LoadScrollPosition() { if (this._requestValueCollection != null) { string text1 = this._requestValueCollection[“__SCROLLPOSITIONX”]; if ((text1 != null) && !int.TryParse(text1, out this._scrollPositionX)) this._scrollPositionX = 0; string text2 = this._requestValueCollection[“__SCROLLPOSITIONY”]; if ((text2 != null) && !int.TryParse(text2, out this._scrollPositionY)) this._scrollPositionY = 0; } } Since the current Page is processing the asynchronous request made by the current client-side PageRequestManager instance, and since the _requestValueCollection contains only the name/ value pairs that the current client-side PageRequestManager instance stuffed into the body of the request, you may be wondering where the scroll x and y values come from. The answer lies in Listing 22-22 itself, which is partially repeated in the following code listing. Recall that this code listing contains the code for the _onFormSubmit method of the current client-side PageRequestManager instance. As discussed earlier, this method is automatically invoked when a post- back occurs. As the highlighted portions of the following code listing show, the current client-side PageRequestManager instance iterates through all the input form elements on the page, including the hidden fields named __SCROLLPOSITIONX and __SCROLLPOSITIONY , and forms for each input form element one string that consists of two substrings, the first containing the value of the name HTML attribute of the input form element (in this case, these values are __SCROLLPOSITIONX and __SCROLLPOSITIONY ) and the second containing the value of the value HTML attribute of the input form element (in this case, these values are the scroll x and y positions). As the boldface portion of the following code listing shows, the current client-side PageRequestManager instance stores the current scroll x and y positions in an internal field named _scrollPostion before it submits the request to the server. As you’ll see later, when the server response arrives, the current client-side PageRequestManager instance retrieves the new scroll x and y positions from the response and compares them with the old values stored in the _scrollPosition field to determine whether the scroll x and y positions have indeed changed. function Sys$WebForms$PageRequestManager$_onFormSubmit(evt) { . . . if (tagName === ‘INPUT’) { var type = element.type; if ((type === ‘text’) || (type === ‘password’) || (type === ‘hidden’) || (((type === ‘checkbox’) || (type === ‘radio’)) && element.checked)) { formBody.append(name); formBody.append(‘=’); c23.indd 1110c23.indd 1110 8/20/07 8:41:23 PM8/20/07 8:41:23 PM Chapter 23: Asynchronous Partial Page Rendering 1111 formBody.append(encodeURIComponent(element.value)); formBody.append(‘&’); } } . . . } . . . this._scrollPosition = this._getScrollPosition(); . . . } InitRecursive I covered the non-postback-related parts of the InitRecursive life cycle phase of the Page object in Chapter 21 ; therefore I’ll just cover the postback-related parts of this phase in this section. Recall from Chapter 21 that the OnInit method of the current ScriptManager instance is automatically invoked when the current Page enters its Init phase. Listing 23-5 presents the ScriptManager class’s internal implementation of the OnInit method, which it inherits from the Control base class. I discussed all the parts of Listing 23-6 in Chapter 21 except for the highlighted portion, which is applicable only to post- back requests. As you can see, this portion calls the IsAsyncPostBackRequest static method on the server-side PageRequestManager , passing in the NameValueCollection that contains the names and values of the request headers. The main responsibility of this method is to determine whether the current request is an asynchronous page postback. Listing 23-5: The OnInit Method of the ScriptManager Class protected override void OnInit(EventArgs e) { base.OnInit(e); if (ScriptManager.GetCurrent(this.Page) != null) throw new InvalidOperationException(“OnlyOneScriptManager”); this.IPage.Items[typeof(ScriptManager)] = this; this.IPage.PreRenderComplete += new EventHandler(this.OnPagePreRenderComplete); if (this.IPage.IsPostBack) this._isInAsyncPostBack = PageRequestManager.IsAsyncPostBackRequest(this.IPage.Request.Headers); this.PageRequestManager.OnInit(); } The IsAsyncPostBackRequest Method of the PageRequestManager Listing 23-6 presents the internal implementation of this method. As you can see, the IsAsyncPostBackRequest method first calls the GetValues method on the NameValueCollection that contains the names and values of the request headers, in order to access all the values of the request header named “X-MicrosoftAjax” : string[] textArray1 = headers.GetValues(“X-MicrosoftAjax”); c23.indd 1111c23.indd 1111 8/20/07 8:41:23 PM8/20/07 8:41:23 PM Chapter 23: Asynchronous Partial Page Rendering 1112 Then it iterates through these values searching for a value that contains the string “Delta=true” . If it finds a value that contains this string, it returns true to signal its caller that the current request is an asynchronous page postback. Listing 22-22 contains the client-side code that made the current asynchronous page postback. The fol- lowing code listing repeats a portion of Listing 22-22 . As the highlighted portion of the following code shows, the current client-side PageRequestManager instance added the “Delta=true” header value to a custom request header named “X-MicrosoftAjax” to signal the server-side PageRequestManager instance that the current request is an asynchronous page postback. function Sys$WebForms$PageRequestManager$_onFormSubmit(evt) { . . . var request = new Sys.Net.WebRequest(); request.set_url(form.action); request.get_headers()[‘X-MicrosoftAjax’] = ‘Delta=true’; request.get_headers()[‘Cache-Control’] = ‘no-cache’; . . . } Listing 23-6: The IsAsyncPostBackRequest Static Method of the PageRequestManager Class internal static bool IsAsyncPostBackRequest(NameValueCollection headers) { string[] textArray1 = headers.GetValues(“X-MicrosoftAjax”); if (textArray1 != null) { for (int num1 = 0; num1 < textArray1.Length; num1++) { string[] textArray2 = textArray1[num1].Split(new char[] { ‘,’ }); for (int num2 = 0; num2 < textArray2.Length; num2++) { if (textArray2[num2].Trim() == “Delta=true”) return true; } } } return false; } The OnInit Method of PageRequestManager Recall from Chapter 21 that the OnInit method of the current server-side PageRequestManager instance is automatically invoked when the Page object enters its Init life cycle phase. Listing 23-7 pres- ents the internal implementation of the OnInit method of the server-side PageRequestManager . I cov- ered all the parts of this method in Chapter 21 , except for the highlighted portion, because this portion is run only when the current request is an asynchronous page postback. As you can see, this portion simply registers the OnPageError method of the current server-side PageRequestManager instance as an event handler for the Error event of the current Page object. c23.indd 1112c23.indd 1112 8/20/07 8:41:23 PM8/20/07 8:41:23 PM Chapter 23: Asynchronous Partial Page Rendering 1113 Listing 23-7: The OnInit Method of the PageRequestManager Class internal void OnInit() { . . . if (this._owner.IsInAsyncPostBack) this._owner.IPage.Error += new EventHandler(this.OnPageError); } Load Post Data Currently we’re at the Load Post Data life cycle phase, in which the ProcessRequest method (see Listing 21-1 ) invokes the ProcessPostData method of the current Page , passing in two parameters. The first parameter is the _requestValueCollection field of the current Page . Recall that this field is a col- lection of type NameValueCollection that contains one name/value pair for each posted data item, the name part containing the UniqueID property value of a server control and the value part containing the value associated with that server control. For example, the name part of the name/value pair associ- ated with a TextBox server control contains the value of the UniqueID property of the TextBox control, and the value part contains the text that the end user has entered into the text field. As Listing 21-1 shows, the ProcessRequest method of the current Page passes true as the second argu- ment of the ProcessPostData method to instruct this method that the Page is currently in a pre-Load life cycle phase. As you’ll see later, the same ProcessPostData method will also be called after the Load life cycle phase. The second Boolean argument allows this method to distinguish between these two calls. Listing 23-8 presents the internal implementation of the ProcessPostData method of the Page . Listing 23-8: The ProcessPostData Method of the Page Object private void ProcessPostData(NameValueCollection postData, bool fBeforeLoad) { if (this._changedPostDataConsumers == null) this._changedPostDataConsumers = new ArrayList(); foreach (string text1 in postData) { if (!Page.IsSystemPostField(text1)) { Control control1 = this.FindControl(text1); if (control1 == null) { if (fBeforeLoad) { if (this._leftoverPostData == null) this._leftoverPostData = new NameValueCollection(); this._leftoverPostData.Add(text1, null); } } else { IPostBackDataHandler handler1 = control1 as IPostBackDataHandler; (continued) c23.indd 1113c23.indd 1113 8/20/07 8:41:24 PM8/20/07 8:41:24 PM Chapter 23: Asynchronous Partial Page Rendering 1114 Listing 23-8 (continued) if (handler1 == null) { if (control1 as IPostBackEventHandler != null) this.RegisterRequiresRaiseEvent(control1.PostBackEventHandler); } else { if (handler1.LoadPostData(text1, this._requestValueCollection)) this._changedPostDataConsumers.Add(control1); if (this._controlsRequiringPostBack != null) this._controlsRequiringPostBack.Remove(text1); } } } } ArrayList list1 = null; if (this._controlsRequiringPostBack != null) { foreach (string text2 in this._controlsRequiringPostBack) { Control control2 = this.FindControl(text2); if (control2 != null) { IPostBackDataHandler handler2 = control2 as IPostBackDataHandler; if (handler2.LoadPostData(text2, this._requestValueCollection)) this._changedPostDataConsumers.Add(control2); } else if (fBeforeLoad) { if (list1 == null) list1 = new ArrayList(); list1.Add(text2); } } this._controlsRequiringPostBack = list1; } } This method first instantiates an ArrayList field named _changePostDataConsumers , if it hasn’t already been instantiated. You’ll see the significance of this field later. if (this._changedPostDataConsumers == null) this._changedPostDataConsumers = new ArrayList(); Next, it iterates through the name/value pairs in the NameValueCollection passed into it as its first argument, and takes the following actions for each enumerated name/value pair if the name part of the pair does not contain the name attribute value of one of the standard hidden fields such as __VIEWSTATE (the name/value pairs associated with standard hidden fields will be processed later): ❑ The ProcessPostData method calls the FindControl method on the current Page object to return a reference to the server control whose UniqueID property value is given by the name part of the enumerated name/value pair: c23.indd 1114c23.indd 1114 8/20/07 8:41:24 PM8/20/07 8:41:24 PM [...]... encoded As Listing 2 3-1 5 shows, the EncodeString method generates a string that contains four substrings separated by the | character, where the second, third, and fourth substrings contain the second and third parameters, and the encoded form of the fourth parameter, of the EncodeString method 1 123 c23.indd 1 123 8/20/07 8:41:27 PM Chapter 23: Asynchronous Partial Page Rendering Listing 2 3-1 5: The EncodeString... class Listing 2 3-1 3 presents the implementation of the Render method of the Control base class Listing 2 3-1 3: The Render Method of the Control Base Class protected internal override void Render(HtmlTextWriter writer) { this.RenderChildren(writer); } As you can see, the Render method of the Control base class simply calls the RenderChildren method shown in Listing 2 3-1 4 Recall from Listing 2 3-1 2 that the... builder1.Append(“,”); (continued) 1139 c23.indd 1139 8/20/07 8:41:33 PM Chapter 23: Asynchronous Partial Page Rendering Listing 2 3-2 8 (continued) flag1 = false; if (includeQuotes) builder1.Append(“’”); builder1.Append(list[num1].UniqueID); if (includeQuotes) builder1.Append(“’”); } } return builder1.ToString(); } The GetPostBackControlIDs Method of the Server-Side PageRequestManager Listing 2 3-2 9 presents the implementation... that were passed into it into the LoadPostData method of the current server-side PageRequestManager instance 1117 c23.indd 1117 8/20/07 8:41:25 PM Chapter 23: Asynchronous Partial Page Rendering The LoadPostData Method of PageRequestManager Listing 2 3-1 0 presents the internal implementation of the LoadPostData method of the server-side PageRequestManager Recall that when the LoadPostData method of the... } } 1131 c23.indd 1131 8/20/07 8:41:30 PM Chapter 23: Asynchronous Partial Page Rendering The ProcessUpdatePanels method first checks whether the _updatePanelRequiresUpdate field of the current server-side PageRequestManager instance contains the UniqueID property value of the enumerated UpdatePanel server control Recall from Listing 2 3-1 0 that the LoadPostData method of the current server-side PageRequestManager... object that the _updatePanelWriter field references Recall from Listing 2 3-1 6 that the RenderPageCallback method of the PageRequestManager stores a reference to the HtmlTextWriter object that wraps the response output stream in the _updatePanelWriter field Therefore, the RenderControl method of the enumerated UpdatePanel 1136 c23.indd 1136 8/20/07 8:41:32 PM Chapter 23: Asynchronous Partial Page Rendering... this.IPage.VerifyRenderingInServerForm(this); base.Render(writer); } 1137 c23.indd 1137 8/20/07 8:41:32 PM Chapter 23: Asynchronous Partial Page Rendering Listing 2 3-2 6 presents the implementation of the RenderChildren method of the UpatePanel server control This method checks whether the UpdatePanel control is in asynchronous postback mode Recall from Listing 2 3-2 1 that the ProcessUpdatePanels method calls the SetAsyncPostBackMode... delegate, which in turn invokes the 1122 c23.indd 1122 8/20/07 8:41:27 PM Chapter 23: Asynchronous Partial Page Rendering PageRenderCallback method of the server-side PageRequestManager The end result of all this is that the server-side PageRequestManager takes complete control over what gets rendered when the current request is an asynchronous page postback Listing 2 3-1 4: The RenderChildren Method of the... cycle phase of the Page was thoroughly discussed in Chapter 21 In this section, I’ll focus only on the postback-related topics that weren’t covered in Chapter 21 As we discussed in Chapter 21, the OnPreRender method of the current ScriptManager server control is automatically invoked when the current page enters its PreRender life cycle phase Listing 2 3-1 1 presents the internal implementation of the OnPreRender... collection of the current server-side PageRequestManager instance As Listing 2 3-2 1 shows, the SetAsyncPostBackMode method sets an internal flag of the specified UpdatePanel server control, named _asyncPostBackMode, to true if (updatePanelNeedsToUpdate) { panel1.SetAsyncPostBackMode(true); this._updatePanelsToRefresh.Add(panel1); } 1134 c23.indd 1134 8/20/07 8:41:31 PM Chapter 23: Asynchronous Partial Page . request header named “X-MicrosoftAjax” : string[] textArray1 = headers.GetValues(“X-MicrosoftAjax”); c23.indd 1111c23.indd 1111 8/20/07 8:41 :23 PM8/20/07 8:41 :23 PM Chapter 23: Asynchronous Partial. synchronous or asynchronous. c23.indd 1109c23.indd 1109 8/20/07 8:41 :23 PM8/20/07 8:41 :23 PM Chapter 23: Asynchronous Partial Page Rendering 1110 Listing 2 3-4 : The LoadScrollPosition Method. of the EncodeString method. c23.indd 1123c23.indd 1 123 8/20/07 8:41:27 PM8/20/07 8:41:27 PM Chapter 23: Asynchronous Partial Page Rendering 1124 Listing 2 3-1 5: The EncodeString Method of