Tải bản đầy đủ (.pdf) (96 trang)

ASP.NET AJAX Programmer’s Reference - Chapter 24 ppsx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (625.95 KB, 96 trang )

Asynchronous Partial Page
Rendering: Client-Side
Processing
The previous chapter followed the Page through its life cycle phases to process the asynchronous
page postback request made by the current client-side
PageRequestMananger instance. We
followed the request from the time it arrived in ASP.NET to the time the server response text was
finally sent back to the client.
This chapter will move on to the client side, where this server response text arrives, and follow the
client-side
PageRequestManager instance through its life cycle phases to process the server
response.
Arrival of the Server Response Text
Recall from Listing 22-22 that the _onFormSubmit method of the current client-side

PageRequestManager instance is where the current client-side PageRequestManager instance
made its asynchronous page postback to the server. Listing 24-1 presents a portion of the

_onFormSubmit method. As the highlighted portion of this code listing shows, the current
client-side
PageRequestManager instance registers its _onFormSubmitCompleted method as
an event handler for the
completed event of the WebRequest object that represents the current
request.
request.add_completed(Function.createDelegate(this,
this._onFormSubmitCompleted));
As the name suggests, the WebRequest object fires its completed event when the current request
is finally completed.
c24.indd 1179c24.indd 1179 8/20/07 8:47:44 PM8/20/07 8:47:44 PM
Chapter 24: Asynchronous Partial Page Rendering
1180


Listing 24-1: The _onFormSubmit Method of the Client-Side PageRequestManager
Instance
function Sys$WebForms$PageRequestManager$_onFormSubmit(evt)
{
. . .
var formBody = new Sys.StringBuilder();
formBody.append(this._scriptManagerID + ‘=’ +
this._postBackSettings.panelID + ‘&’);
var count = form.elements.length;
for (var i = 0; i < count; i++)
{
. . .
}
. . .
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’;
request.set_timeout(this._asyncPostBackTimeout);
request.add_completed(Function.createDelegate(this,
this._onFormSubmitCompleted));
request.set_body(formBody.toString());
. . .
this._request = request;
request.invoke();
. . .
}
Recall from Listing 12-41 of Chapter 12 that when the request is finally completed, the
_onReadyStateChange method of the current XMLHttpExecutor is invoked, as shown again in
Listing 24-2 . As you can see from the highlighted portion of this code listing, the

_onReadyStateChange
method invokes the
completed method on the WebRequest object that represents the current request.
Listing 24-2: The _onReadyStateChange Method
this._onReadyStateChange = function ()
{
if (_this._xmlHttpRequest.readyState === 4 /*complete*/)
{
_this._clearTimer();
_this._responseAvailable = true;
_this._webRequest.completed(Sys.EventArgs.Empty);
if (_this._xmlHttpRequest != null)
{
_this._xmlHttpRequest.onreadystatechange = Function.emptyMethod;
_this._xmlHttpRequest = null;
}
}
}
c24.indd 1180c24.indd 1180 8/20/07 8:47:45 PM8/20/07 8:47:45 PM
Chapter 24: Asynchronous Partial Page Rendering
1181
Recall from Listing 12-11 of Chapter 12 that the completed method of the WebRequest object in turn
calls the event handlers registered for the
completed event of the WebRequest object, as shown again in
the highlighted portion of Listing 24-3 .
Listing 24-3: The Completed Method
function Sys$Net$WebRequest$completed(eventArgs)
{
var handler = Sys.Net.WebRequestManager._get_eventHandlerList().getHandler(
“completedRequest”);

if (handler)
handler(this._executor, eventArgs);
handler = this._get_eventHandlerList().getHandler(“completed”);
if (handler)
handler( this._executor , eventArgs);
}
As the boldface portion of Listing 24-3 shows, when the completed method of the WebRequest
object invokes the event handlers registered for its
completed event, it passes a reference to the

WebRequestExecutor object responsible for executing the current request. This means that the first
parameter of the
_onFormSubmitCompleted method of the current client-side PageRequestManager
instance references this
WebResquestExecutor object. You’ll see the internal implementation of the
_onFormSubmitCompleted method later in the chapter.
As I mentioned earlier, our goal in this chapter is to follow the current
PageRequestMananger instance
through its life cycle phases to process the server response. Since the current
PageRequestManager
instance’s life cycle is rather complex and involves a lot of method calls, I’ve captured almost all of them
in a two-part diagram shown in Figures 24-1 and 24-2 to make it easier for you to follow our discussions.
The vertical axis in this two-part diagram measures increasing time (early on the top, late on the bottom).
Keep this two-part diagram in mind as you’re reading through this chapter. Also keep in mind where we
are on this diagram at every stage of the current
PageRequestManager instance’s life cycle.
As you can see from Listing 24-3 , the
_onFormSubmitCompleted method of the current

PageRequestManager instance sets the _processingRequest field on the current client-

side
PageRequestManager instance to true to signal that the request is now being processed:
this._processingRequest = true;
Just because the WebRequest object has fired the completed event and consequently called the
_onFormSubmitCompleted method does not mean that everything went fine and the server response
has arrived. The
WebRequest object fires the completed event for a number of reasons. Therefore, the
_onFormSubmitCompleted method takes the following steps to determine why the completed event
was raised. First, it calls the
get_timedOut method on the WebRequestExecutor object to return a
c24.indd 1181c24.indd 1181 8/20/07 8:47:45 PM8/20/07 8:47:45 PM
Chapter 24: Asynchronous Partial Page Rendering
1182
Boolean value that specifies whether the completed event was raised because of a timeout. If so, it calls
the
_endPostBack method on the current PageRequestManager instance to end the ongoing asynchro-
nous postback request and returns the following:
if (sender.get_timedOut())
{
this._endPostBack(this._createPageRequestManagerTimeoutError(), sender);
return;
}
Next, it calls the get_aborted method on the WebRequestExecutor to return a Boolean value that
specifies whether the
completed event was raised because the request aborted. If so, it calls the
_endPostBack method on the current PageRequestManager instance to end the ongoing request
and returns this:
if (sender.get_aborted())
{
this._endPostBack(null, sender);

return;
}
Next, the _onFormSubmitCompleted method calls the get_webRequest method on the

WebRequestExecutor to return a reference to the WebRequest object that represents the request that
the
WebRequestExecutor executed. It then compares this with the WebRequest object that the
_request property of the current PageRequestManager instance references. (As the boldface portion
PageRequestManager (Processing Server Response) - First Part
PageRequestManager
_childUpdatePanelIDs _panelsToRefreshIDs
WebRequestExecutor
EventHandlerList
_endPostBack ()
_onFormSubmitCompleted ()
_endPostBack ()
get_timedOut ()
get_aborted ()
get_statusCode ()
_endPostBack ()
get_responseData ()
_endPostBack ()
add (dataItem)
getHandler (‘‘pageLoading’’)
_endPostBack ()
innerHTML= htmlMarkup
_updateControls (updatePanelIDs, asyncPostBackControlIDs,
postBackControlIDs, asyncPostBackTimeout)
_endPostBack ()
_updatePanel (updatePanelID, htmlMarkup)

get_webRequest ()
add(updatePanelID)
window
_dataItems
eval (_scriptDisposes[updatePanelID])
_destroyTree (updatePanel ID)
add(updatePanelID)
upadatePanelDOMElement
Time Axis
_endPostBack is invoked when get_timedOut returns true
_endPostBack is invoked when get_aborted returns true
_endPostBack is invoked when get_statusCode does not returns 200
_endPostBack is invoked when the response text contains an error
or unrecognized type
_endPostBack is invoked if _panelsToRefreshIDs contains the
UniqueID of a non-existent UpdatePanel
_endPostBack is invoked if the UpdatePanel control whose content
being updated is non-existent
Figure 24-1
c24.indd 1182c24.indd 1182 8/20/07 8:47:45 PM8/20/07 8:47:45 PM
Chapter 24: Asynchronous Partial Page Rendering
1183
of Listing 24-1 shows, the current PageRequestManager instance assigns the WebRequest object to
an internal field named
_request before it executes the request.) If these two WebRequest objects
are different, the
completed event was raised for a different request and consequently the
_onFormSubmitCompleted method simply returns this:
if (!this._request || sender.get_webRequest() !== this._request)
return;

As you can see, if an application makes several overlapping asynchronous page postback requests to the
server, the last request wins.
Next, the
_onFormSubmitCompleted method calls the get_statusCode method on the

WebRequestExecutor object to return an integer that contains the response status code. If this code
is not
200 , it is an indication that a server error occurred, and consequently the method calls the
_endPostBack method on the current PageRequestManager instance to end the current request and
returns this:
if (sender.get_statusCode() !== 200)
{
this._endPostBack(
this._createPageRequestManagerServerError(sender.get_statusCode()), sender);
return;
}
PageRequestManager
_scriptDisposes
[updatePanelID]
_registerDisposeScript (updatePanelID, disposeScript)
add (disposeScript)
_loadScriptsInternal ()
nextScript= dequeue ()
WebForm AutoFocus (controlIDToFocus)
scrollTo (_scrollPosition.x,_scrollPosition.y)
document
hiddenField= createElement (‘input’)
document
existingScripts= getElementsByTagName (‘SCRIPT’)
_ScriptLoader

readLoadedScripts ()
_getInstance ()
queueScriptBlock (arrayScript)
queueScriptBlock (expandoScript)
queueScriptReference (scriptUrl)
add (arrayScript)
add (expandoScript)
add (scriptUrl)
add (scriptAttributes)
add (onSubmitStatementScript)
queueCustomScriptTag (scriptAttributes)
queueScriptBlock (onSubmitStatementScript)
_pageLoaded ()
scriptElement= _createScriptElement (nextScript)
getHandler (‘‘pageLoaded’’)
_endPostBack ()
loadScripts ()
_referencedScripts
_scriptsToLoad
add(existingScripts)
_ScriptLoaderTask
new Sys. ScriptLoaderTask(scriptElement,_scriptLoadedDelegate)
execute ()
appendChild (scriptElement)
scriptsLoadComplete ()
EventHandlerList
headElement
Time Axis
_form
window

appendChild (hiddenField)
PageRequestManager (Processing Server Response) - Second Part
Figure 24-2
c24.indd 1183c24.indd 1183 8/20/07 8:47:46 PM8/20/07 8:47:46 PM
Chapter 24: Asynchronous Partial Page Rendering
1184
Next, the _onFormSubmitCompleted method calls the get_responseData method on the

WebRequestExecutor object to return the string that contains the server response:
var reply = sender.get_responseData();
Recall from Listing 23-52 that the server response text is a string that contains a bunch of substrings in
the format
length|type|id|content , where:
❑ The length part tells the current client-side PageRequestManager instance how many
characters there are in the
content part of the substring.
❑ The type part tells the current client-side PageRequestManager instance what type of
information the
content part contains.
❑ The optional id part specifies the ClientID property value of the server control associated with
the information contained in the
content part.
❑ The content part contains the actual information that the current server-side

PageRequestManager instance has sent to the current client-side PageRequestManager
instance.
Listing 24-4 contains an example of a server response text that the current server-side
PageRequestManager
instance sends to the current client-side
PageRequestManager instance. Keep this code listing in mind as

we’re walking through the implementation of the
_onFormSubmitCompleted method. The main
responsibility of this method is to parse a response text similar to Listing 24-4 .
Listing 24-4: An Example of a Server Response Text that the Current Client-Side
PageRequestManager Might Receive
586|updatePanel|UpdatePanel1|
<table>
<tr>
<td>
First Name:</td>
<td>
<input name=”TextBox1” type=”text” value=”Shahram” id=”TextBox1”
/></td>
</tr>
<tr>
<td>
Last Name:</td>
<td>
<input name=”TextBox2” type=”text” value=”Khosravi” id=”TextBox2”
/></td>
</tr>
<tr>
<td colspan=”2” align=”center”>
<input type=”submit” name=”Button1” value=”Submit” id=”Button1”
/></td>
</tr>
</table>
c24.indd 1184c24.indd 1184 8/20/07 8:47:46 PM8/20/07 8:47:46 PM
Chapter 24: Asynchronous Partial Page Rendering
1185

|52|hiddenField|__VIEWSTATE|/wEPDwULLTIxMjYzMDU2NzJkZJ0ptWJFvcbB8l53OBKz9PRMaPrd|64
|hiddenField|__EVENTVALIDATION|/wEWBAKj4cTUAgLs0bLrBgLs0fbZDAKM54rGBv6aI9H0BYIx273P
dOWCCpAOOHzF|0|asyncPostBackControlIDs|||0|postBackControlIDs|||13|updatePanelIDs||
tUpdatePanel1|0|childUpdatePanelIDs|||12|panelsToRefreshIDs||UpdatePanel1|2|asyncPo
stBackTimeout||90|12|formAction||Default.aspx|13|pageTitle||Untitled Page
The _onFormSubmitCompleted method recursively takes the following steps to parse each substring in
the server response string:
❑ It accesses the index of the first delimiter | character of the substring:
delimiterIndex = reply.indexOf(‘|’, replyIndex);
❑ If the substring does not contain this delimiter, the _onFormSubmitCompleted method calls
another method named
_findText , stores the return value of this method in a local field named

parserErrorDetails , and exits the while loop that loops through the substrings in the server
response string. In other words, it does not attempt to parse the rest of the server response
string. There is no point in processing an erroneous server response. As you’ll see shortly, the
first statement after this
while loop checks whether the value of the parserErrorDetails
field is set. If so, it takes the appropriate action to end the current request.
if (delimiterIndex === -1)
{
parserErrorDetails = this._findText(reply, replyIndex);
break;
}
❑ The following code listing presents the implementation of the _findText method:
function Sys$WebForms$PageRequestManager$_findText(text, location)
{
var startIndex = Math.max(0, location - 20);
var endIndex = Math.min(text.length, location + 20);
return text.substring(startIndex, endIndex);

}
❑ The _onFormSubmitCompleted method parses the first part (that is, the length part) of the
substring:
len = parseInt(reply.substring(replyIndex, delimiterIndex), 10);
replyIndex = delimiterIndex + 1;
❑ It accesses the index of the second delimiter:
delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
❑ If the substring does not contain this delimiter, the _onFormSubmitCompleted method calls the

_findText method, stores the return value of this method in the parserErrorDetails local
field, and exits the
while loop, as discussed earlier.
c24.indd 1185c24.indd 1185 8/20/07 8:47:46 PM8/20/07 8:47:46 PM
Chapter 24: Asynchronous Partial Page Rendering
1186
if (delimiterIndex === -1)
{
parserErrorDetails = this._findText(reply, replyIndex);
break;
}
❑ The _onFormSubmitCompleted method parses the second part (that is, the type part) of the
substring:
type = reply.substring(replyIndex, delimiterIndex);
replyIndex = delimiterIndex + 1;
❑ It accesses the index of the third delimiter | :
delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
❑ If the substring does not contain this delimiter, the _onFormSubmitCompleted method calls the

_findText method, stores the return value of this method in the parserErrorDetails local
field, and exits the

while loop, as discussed earlier.
if (delimiterIndex === -1)
{
parserErrorDetails = this._findText(reply, replyIndex);
break;
}
❑ The _onFormSubmitCompleted method parses the third part (that is, the id part) of the
substring:
id = reply.substring(replyIndex, delimiterIndex);
replyIndex = delimiterIndex + 1;
❑ Recall that the len local field contains the length of the content part of the substring.
_onFormSubmitCompleted first checks whether the index of the expected last character of the
content part of the substring is a value that exceeds the length of the substring. If so, this is an
indication that the server response has problems and consequently
_onFormSubmitCompleted
takes the same steps discussed earlier and exits the
while loop.
if ((replyIndex + len) >= reply.length)
{
parserErrorDetails = this._findText(reply, reply.length);
break;
}
❑ The _onFormSubmitCompleted method accesses the fourth part (that is, the content part) of
the substring. (Note that the length of the fourth part is given by the first part of the

length|type|id|content format.)
content = this._decodeString(reply.substr(replyIndex, len));
replyIndex += len;
c24.indd 1186c24.indd 1186 8/20/07 8:47:47 PM8/20/07 8:47:47 PM
Chapter 24: Asynchronous Partial Page Rendering

1187
❑ Next, _onFormSubmitCompleted checks whether the last character of the substring is the
delimiter character (|). If not, this is an indication that the server response has problems and
consequently
_onFormSubmitCompleted method takes the same steps discussed earlier
and exits the
while loop.
if (reply.charAt(replyIndex) !== delimitByLengthDelimiter)
{
parserErrorDetails = this._findText(reply, replyIndex);
break;
}
❑ The _onFormSubmitCompleted method creates an object literal with three name/value
pairs. The name part of the first pair is the word
type and its value part is the second part of the
substring (that is, the
type part). The name part of the second name/value pair is the word id
and its value part is the third part of the substring (that is, the
id part). The name part of the
third name/value pair is the word
content and its value part is the fourth part of the substring
(that is, the
content part).
var obj = {type: type, id: id, content: content};
❑ The _onFormSubmitCompleted method stores the above object literal in a local array named

delta .
Array.add(delta, obj);
As you can see, the _onSubmitFormCompleted method parses each substring (in the


length|type|id|content format) into an object literal and stores the object in a local array
named
delta .
After existing the
while loop, the _onSubmitFormCompleted method first checks whether the value of
the
parseErrorDetails local field is set. If so, this is an indication that the server response had some
problems and consequently
_onSubmitFormCompleted invokes the _endPostBack method to end the
current asynchronous page postback request.
if (parserErrorDetails)
{
this._endPostBack(this._createPageRequestManagerParserError(
String.format(Sys.WebForms.Res.PRM_ParserErrorDetails,
parserErrorDetails)), sender);
return;
}
Next, the method iterates through the object literals in the delta array and checks the value of the type
property of each enumerated object (recall that the value associated with the
type property of the object
contains the second part of the
length|type|id|content format):
❑ If the type is the string “updatePanel” , the _onFormSubmitCompleted method adds the
enumerated object to a local array named
updatePanelNodes . The value of the id property of
this object is a string that contains the value of the
UniqueID property of an UpdatePanel
c24.indd 1187c24.indd 1187 8/20/07 8:47:47 PM8/20/07 8:47:47 PM
Chapter 24: Asynchronous Partial Page Rendering
1188

server control. The value of the content property of this object is a string that contains the
markup text for this
UpdatePanel server control.
case “updatePanel”:
Array.add(updatePanelNodes, deltaNode);
break;
❑ If the type is the string “hiddenField” , the _onFormSubmitCompleted method adds the
enumerated object to a local array named
hiddenFieldNodes . The value of the id property of
this object is a string that contains the name of the hidden field and the value of the content
property is a string that contains the value of the hidden field.
case “hiddenField”:
Array.add(hiddenFieldNodes, deltaNode);
break;
❑ If the type is the string “arrayDeclaration” , the _onFormSubmitCompleted method adds
the enumerated object to a local array named
arrayDeclarationNodes . This object describes
an array declaration in which the value of the
id property of the object is a string that contains
the name of the JavaScript array. The value of the
content property of this object is a string that
contains the value being added to the array.
case “arrayDeclaration”:
Array.add(arrayDeclarationNodes, deltaNode);
break;
❑ If the type is the string “scriptBlock” , the _onFormSubmitCompleted method adds the
enumerated object to a local array named
scriptBlockNodes . This object describes a script
block in which the value of the
id property of the object is one of the following string values:


“ScriptContentNoTags” , “ScriptContentWithTags” , or “ScriptPath”, and in which the
value of the
content property is a string that contains the associated script block:
case “scriptBlock”:
Array.add(scriptBlockNodes, deltaNode);
break;
❑ If the type is the string “expando” , the _onFormSubmitCompleted method adds the
enumerated object to a local array named
expandoNodes . This object describes an expando
attribute in which the value of the
id property of the object is a string that contains the name of
the
expando attribute, and the value of the content property is a string that contains the value
of the
expando attribute.
case “expando”:
Array.add(expandoNodes, deltaNode);
break;
❑ If the type is the string “onSubmit” , the _onFormSubmitCompleted method adds the enumer-
ated object to a local array named
onSubmitNodes . This object describes a dynamically added
form
onsubmit statement in which the value of the id property of the object is an empty string
and the value of the
content property of the object is a string that contains the dynamically
added form
onsubmit statement.
c24.indd 1188c24.indd 1188 8/20/07 8:47:47 PM8/20/07 8:47:47 PM
Chapter 24: Asynchronous Partial Page Rendering

1189
case “onSubmit”:
Array.add(onSubmitNodes, deltaNode);
break;
❑ If the type is the string “asyncPostBackControlIDs” , the _onFormSubmitCompleted
method assigns the enumerated object to a local field named
asyncPostBackControlIDsNode .
This object describes all the server controls on the page that cause asynchronous page postbacks.
The value of the
id property of this object is an empty string, and the value of the content
property is a string that contains a comma-separated list of substrings, each substring containing
the value of the
UniqueID property of a server control that causes an asynchronous page
postback.
case “asyncPostBackControlIDs”:
asyncPostBackControlIDsNode = deltaNode;
break;
❑ If the type is the string “postBackControlIDs” , the _onFormSubmitCompleted method
assigns the enumerated object to a local field named
postBackControlIDsNode . This object
describes all the server controls on the page that cause normal synchronous page postbacks. The
value of the
id property of this object is an empty string, and the value of the content property
is a string that contains a comma-separated list of substrings, each substring containing the
value of the
UniqueID property of a server control that causes a synchronous page postback.
case “postBackControlIDs”:
postBackControlIDsNode = deltaNode;
break;
❑ If the type is the string “updatePanelIDs” , the _onFormSubmitCompleted method assigns

the enumerated object to a local field named updatePanelIDsNode . This object describes all the

UpdatePanel server controls on the current page. The value of the id property of this object is
an empty string, and the value of the
content property is a string that contains a comma-
separated list of substrings, each substring containing the value of the
UniqueID property of an

UpdatePanel server control.
case “updatePanelIDs”:
updatePanelIDsNode = deltaNode;
break;
❑ If the type is the string “asyncPostBackTimeout” , the _onFormSubmitCompleted method
assigns the enumerated object to a local field named
asyncPostBackTimeoutNode . This object
describes timeout value for asynchronous page postbacks. The value of the
id property of this
object is an empty string, and the value of the
content property is a string that contains the
value of the asynchronous page postback timeout:
case “asyncPostBackTimeout”:
asyncPostBackTimeoutNode = deltaNode;
break;
c24.indd 1189c24.indd 1189 8/20/07 8:47:48 PM8/20/07 8:47:48 PM
Chapter 24: Asynchronous Partial Page Rendering
1190
❑ If the type is the string “childUpdatePanelIDs” , the _onFormSubmitCompleted method
assigns the enumerated object to a local field named
childUpdatePanelIDsNode . This object
describes all the child

UpdatePanel server controls on the current page that need updating
because their parent
UpdatePanel server controls need updating. The value of the id property
of this object is an empty string, and the value of the
content property is a string that contains a
comma-separated list of substrings, each substring containing the value of the
UniqueID
property of a child
UpdatePanel server control.
case “childUpdatePanelIDs”:
childUpdatePanelIDsNode = deltaNode;
break;
❑ If the type is the string “panelsToRefreshIDs” , the _onFormSubmitCompleted method
assigns the enumerated object to a local field named
panelsToRefreshNode . This object
describes all the
UpdatePanel server controls on the current page that need updating. The
value of the
id property of this object is an empty string, and the value of the content property
is a string that contains a comma-separated list of substrings, each substring containing the
value of the
UniqueID property of an UpdatePanel server control.
case “panelsToRefreshIDs”:
panelsToRefreshNode = deltaNode;
break;
❑ If the type is the string “formAction” , the _onFormSubmitCompleted method assigns the
enumerated object to a local field named
formActionNode . This object describes the current
form action. The value of the
id property of this object is an empty string, and the value of the


content property is a string that contains the value of the action property of the form.
case “formAction”:
formActionNode = deltaNode;
break;
❑ If the type is the string “dataItem” , the _onFormSubmitCompleted method adds the enumer-
ated object to a local array named
dataItemNodes . This object describes a data item associated
with a server control. The value of the
id property of the object is the value of the ClientID
property of the server control, and the value of the
content property is a string that contains
the string representation of the data item. For example, this string representation could be an
XML representation of the data item.
case “dataItem”:
Array.add(dataItemNodes, deltaNode);
break;
❑ If the type is the string “dataItemJson” , the _onFormSubmitCompleted method adds the
enumerated object to a local array named
dataItemJsonNodes . This object describes a data
item associated with a server control. The value of the
id property of the object is the value of
the
ClientID property of the server control, and the value of the content property is a string
that contains the JSON representation of the data item.
case “dataItemJson”:
Array.add(dataItemJsonNodes, deltaNode);
break;
c24.indd 1190c24.indd 1190 8/20/07 8:47:48 PM8/20/07 8:47:48 PM
Chapter 24: Asynchronous Partial Page Rendering

1191
❑ If the type is the string “scriptDispose” , the _onFormSubmitCompleted method adds the
enumerated object to a local array named
scriptDisposeNodes . This object describes a script
that contains a call into a
dispose method associated with an UpdatePanel server control. The
value of the
id property of the object is the value of the ClientID property of the UpdatePanel
server control, and the value of the
content property is a string that contains the calls into the

dispose method.
case “scriptDispose”:
Array.add(scriptDisposeNodes, deltaNode);
break;
❑ The following code fragment shows an example of the value of the content property. This
example registers the
$find(‘UpdatePanel1’).dispose(); script for the UpdatePanel
server control whose
ClientID property has the value of “UpdatePanel1” :
Sys.WebForms.PageRequestManager.getInstance()._registerDisposeScript(“UpdatePanel1”
,”$find(‘UpdatePanel1’).dispose();”);
❑ If the type is the string “pageRedirect” , the _onFormSubmitCompleted method assigns the
value of the
content property of the enumerated object to the href property of the location
property of the
window object. As you can see, the value of the content property of this object is
a string that contains the URL to which the current window will be redirected:
case “pageRedirect”:
window.location.href = deltaNode.content;

return;
❑ If the type is the string “error” , the enumerated object describes a server error: the value of the

id property of the object is a string that contains the number associated with the error, and the
value of the
content property of the object is a string that contains the error message. As you
can see, the
_onFormSubmitCompleted method calls the _endPostBack method on the current

PageRequestManager instance to end the current request:
case “error”:
this._endPostBack(this._createPageRequestManagerServerError(
Number.parseInvariant(deltaNode.id), deltaNode.content), sender);
return;
❑ If the type is the string “pageTitle” , the enumerated object describes the title of the current
page: the value of the
content property of the object is a string that contains the new title of
the page. Because of this, the
_onFormSubmitCompleted method assigns the value of the

content property to the title property of the document object.
case “pageTitle”:
document.title = deltaNode.content;
break;
c24.indd 1191c24.indd 1191 8/20/07 8:47:48 PM8/20/07 8:47:48 PM
Chapter 24: Asynchronous Partial Page Rendering
1192
❑ If the type is the string “focus” , the enumerated object describes the HTML element that must
have the focus. The value of the
id property of this object is an empty string, and the value of

the
content property is a string that contains the value of the ClientID property of the server
control that must have the focus. As you can see, the _onFormSubmitCompleted method
assigns the value of the
content property of the object to the _controlIDToFocus field of the
current
PageRequestManager instance:
case “focus”:
this._controlIDToFocus = deltaNode.content;
break;
❑ If the type is none of the preceding strings, the _onFormSubmitCompleted method calls the
_endPostBack method on the current PageRequestManager instance to end the current post-
back request:
default:
this._endPostBack(this._createPageRequestManagerParserError(
String.format(Sys.WebForms.Res.PRM_UnknownToken, deltaNode.type)), sender);
return;
Next, the _onFormSubmitCompleted method stores the contents of the _updatePanelIDs array in the

_oldUpdatePanelIDs array field of the current PageRequestManager instance:
this._oldUpdatePanelIDs = this._updatePanelIDs;
Then the method uses the childUpdatePanelIDsNode to populate the _childUpdatePanelIDs array
of the current
PageRequestManager instance. Keep in mind that this array contains the value of the

UniqueID properties of the UpdatePanel server controls that need updating because their parent

UpdatePanel server control needs updating:
var childUpdatePanelIDsString = childUpdatePanelIDsNode.content;
this._childUpdatePanelIDs =

childUpdatePanelIDsString.length ? childUpdatePanelIDsString.split(‘,’) : [];
Next, the method uses the panelsToRefreshNode to populate the _panelsToRefreshIDs array of the
current
PageRequestManager instance. Keep in mind that this array contains the value of the UniqueID
properties of the
UpdatePanel server controls that need updating:
this._panelsToRefreshIDs = this._splitNodeIntoArray(panelsToRefreshNode);
Next the method iterates through the UniqueID property values in the _panelsToRefreshIDs array,
passes each enumerated value into the
_uniqueIDToClientID method to return the value of its
associated
ClientID property, and finally calls the getElementById method, passing in this ClientID
property value to check whether the current page contains an
UpdatePanel server control with the
specified
UniqueID and ClientID property values. If not, it calls the _endPostBack method to end the
current request:
c24.indd 1192c24.indd 1192 8/20/07 8:47:49 PM8/20/07 8:47:49 PM
Chapter 24: Asynchronous Partial Page Rendering
1193
for (i = 0; i < this._panelsToRefreshIDs.length; i++)
{
var panelClientID = this._uniqueIDToClientID(this._panelsToRefreshIDs[i]);
if (!document.getElementById(panelClientID))
{
this._endPostBack(Error.invalidOperation(
String.format(Sys.WebForms.Res.PRM_MissingPanel, panelClientID)), sender);
return;
}
}

Next, the _onFormSubmitCompleted method calls the _splitNodeIntoArray method of the

PageRequestManager three times to convert asyncPostBackControlIDsNode ,

postBackControlIDsNode , and updatePanelIDsNode into arrays:
var asyncPostBackControlIDsArray =
this._splitNodeIntoArray(asyncPostBackControlIDsNode);
var postBackControlIDsArray = this._splitNodeIntoArray(postBackControlIDsNode);
var updatePanelIDsArray = this._splitNodeIntoArray(updatePanelIDsNode);
var asyncPostBackTimeout = asyncPostBackTimeoutNode.content;
Next, it calls the _updateControls method on the current PageRequestManager instance, passing in
the following parameters:
❑ updatePanelIDsArray : This parameter is an array that contains the values of the UniqueID
properties of all
UpdatePanel server controls on the current page after the update. I say “after
the update” because this array has just arrived from the server. Because of this, the content
of the
_updatePanelIDs array of the current PageRequestManager instance could be out of
date: the server code may have added a new
UpdatePanel server control or deleted an existing

UpdatePanel server control.
❑ asyncPostBackControlIDsArray : This parameter is an array that contains the values of the

UniqueID properties of all the server controls on the current page that cause asynchronous page
postbacks.
❑ postBackControlIDsArray : This parameter is an array that contains the values of the

UniqueID properties of all the server controls on the current page that cause normal
synchronous page postbacks.

❑ asyncPostBackTimeout : This parameter is a string that contains the timeout value for
asynchronous page postbacks:
this._updateControls(updatePanelIDsArray, asyncPostBackControlIDsArray,
postBackControlIDsArray, asyncPostBackTimeout);
I thoroughly discussed the _updateControls method of the PageRequestManager in Chapter 22 .
Next, the
_onFormSubmitCompleted method iterates through the objects in the dataItemNodes array
(recall that this array contains all the objects that represent data items) and uses the value of the
id
property of each enumerated object as an index into the
_dataItems collection of the current
c24.indd 1193c24.indd 1193 8/20/07 8:47:49 PM8/20/07 8:47:49 PM
Chapter 24: Asynchronous Partial Page Rendering
1194
PageRequestManager instance to store the value of the content property of the enumerated object into
the collection. Recall that the value of the
content property of the enumerated object is a string that
contains the string representation of the data item associated with the server control whose
UniqueID
property value is given by the value of the
id property of the enumerated object. In other words, each
item in the
_dataItems collection of the current PageRequestManager instance contains the string
representation of a data item associated with a server control that has a specified
UniqueID
property value:
this._dataItems = {};
for (i = 0; i < dataItemNodes.length; i++)
{
var dataItemNode = dataItemNodes[i];

this._dataItems[dataItemNode.id] = dataItemNode.content;
}
Next, the _onFormSubmitCompleted method iterates through the objects in the dataItemJsonNodes
array (recall that this array contains all the objects that represent JSON data items) and uses the value of
the
id property of each enumerated object as an index into the _dataItems collection of the current

PageRequestManager instance to store the value of the content property of the enumerated object into
the collection. Recall that the value of the
content property of the enumerated object is a string that
contains the JSON representation of the data item associated with the server control whose
UniqueID
property value is given by the value of the
id property of the enumerated object:
for (i = 0; i < dataItemJsonNodes.length; i++)
{
var dataItemJsonNode = dataItemJsonNodes[i];
this._dataItems[dataItemJsonNode.id] = eval(dataItemJsonNode.content);
}
Next, the _onFormSubmitCompleted method calls the get_eventHandlerList method on the current

PageRequestManager instance to return a reference to the EventHandlerList that contains all the
event handlers registered for the events of the
PageRequestManager instance. Then it calls the

getHandler method on this EventHandlerList to return a reference to a JavaScript function whose
invocation automatically invokes all the event handlers registered for the
pageLoading event of the
current
PageRequestManager instance:

var handler = this._get_eventHandlerList().getHandler(“pageLoading”);
Next, it calls the _getPageLoadingEventArgs method on the current PageRequestManager instance to
instantiate and return a
PageLoadingEventArgs object. As you’ll see later, the PageLoadingEventArgs
is the event data class for the
pageLoading event of the PageRequestManager class:
var Sys.WebForms.PageLoadingEventArgs args = this._getPageLoadingEventArgs();
Then it calls the previously mentioned JavaScript function and consequently all the event handlers
registered for the
pageLoading event of the current PageRequestManager instance, passing in a
reference to the current
PageRequestManager instance and the PageLoadingEventArgs object:
handler(this, args);
c24.indd 1194c24.indd 1194 8/20/07 8:47:49 PM8/20/07 8:47:49 PM
Chapter 24: Asynchronous Partial Page Rendering
1195
If you register an event handler for the pageLoading event of the current PageRequestManager
instance, your event handler will receive the previously mentioned two references. Your handler can
then use these two references to get the complete information about the current request and use this
information to perform application-specific page-loading tasks.
Next, the
_onFormSubmitCompleted method checks whether the formActionNode local variable is

null . Recall that this variable references the object that describes the action property of the current
form. If the variable is not
null , the method assigns the value of the content property of this object to
the action property of the form. You may be wondering why an asynchronous page postback may end
up changing the
action property of the current form. This normally happens when cookieless sessions
are used, in which the session ID is embedded in the target URL, which changes the

action value:
if (formActionNode)
this._form.action = formActionNode.content;
Next, the method iterates through the objects in the updatePanelNodes array (recall that each object in
this array describes an
UpdatePanel server control that needs updating) and takes the following steps
for each enumerated object. First, it calls the
getElementById method on the document object, passing
in the value of the
id property of the enumerated object. Recall that the value of this property is a string
that contains the value of the ClientID property of the UpdatePanel server control that the object
describes. Therefore, the
getElementById method returns a reference to the DOM element associated
with the
UpdatePanel server control:
var deltaUpdatePanel = updatePanelNodes[i];
var updatePanelElement = document.getElementById(deltaUpdatePanel.id);
If the current page does not contain a DOM element associated with the UpdatePanel
server control, the
_onFormSubmitCompleted method calls the _endPostBack method on the
current
PageRequestManager instance to end the current request:
if (!updatePanelElement)
{
this._endPostBack(Error.invalidOperation(
String.format(Sys.WebForms.Res.PRM_MissingPanel, deltaPanelID)), sender);
return;
}
Next, the method calls the _updatePanel method on the current PageRequestManager instance,
passing in a reference to the DOM element that represents the

UpdatePanel server control and the value
of the
content property of the enumerated object. Recall that the value of this property is a string that
contains the markup text for the
UpdatePanel server control. As you’ll see later, the _updatePanel
server control updates the content of the specified
UpatePanel server control with the specified HTML
markup text.
this._updatePanel(updatePanelElement, deltaUpdatePanel.content);
Next, the method iterates through the objects in the scriptDisposeNodes array. Recall that the value
of the
content property of each object in this array contains a script that disposes the server control
whose
ClientID property value is given by the value of the id property of the object. The
_onFormSubmitCompleted method calls the _registerDisposeScript method on the current

PageRequestManager instance, passing in the values of the id and content properties of the
c24.indd 1195c24.indd 1195 8/20/07 8:47:50 PM8/20/07 8:47:50 PM
Chapter 24: Asynchronous Partial Page Rendering
1196
enumerated object. As you’ll see later, the _registerDisposeScript method of the current

PageRequestManager instances registers the specified dispose script for the specified UpdatePanel
server control:
for (i = 0; i < scriptDisposeNodes.length; i++)
{
var disposePanelId = scriptDisposeNodes[i].id;
var disposeScript = scriptDisposeNodes[i].content;
this._registerDisposeScript(disposePanelId, disposeScript);
}

Next, the method iterates through the objects in the hiddenFieldNodes array. Recall that each object in
this array describes a hidden field for which the value of the
id property of the object contains the value
of the
id HTML attribute of the hidden field, and the value of the content property of the object con-
tains the value that must be stored in the hidden field. The
_onFormSubmitCompleted method takes the
following steps for each enumerated object. First, it calls the
getElementById method on the document
object to check whether the current page already contains a hidden field with the specified
id HTML
attribute value.
var hiddenFieldElement = document.getElementById(hiddenFieldNodes[i].id);
If so, it simply stores the value of the content property of the enumerated object in the existing
hidden field:
hiddenFieldElement.value = value;
If not, it takes the following steps to create a new hidden field. First, it calls the createElement method
on the document object to create a new input HTML element:
hiddenFieldElement = document.createElement(‘input’);
Then it assigns the value of the id property of the enumerated object to the id property of the newly
instantiated input HTML element:
hiddenFieldElement.id = hiddenFieldNodes[i].id;
Next, the _onFormSubmitCompleted method assigns the value of the id property of the enumerated
object to the
name property of the newly instantiated input HTML element:
hiddenFieldElement.name = hiddenFieldNodes[i].id;
Next, it sets the type property of the newly instantiated input HTML element to hidden :
hiddenFieldElement.type = ‘hidden’;
Finally, it calls the appendChild method on the form element to append the newly instantiated hidden
field as the child of the form element:

this._form.appendChild(hiddenFieldElement);
c24.indd 1196c24.indd 1196 8/20/07 8:47:50 PM8/20/07 8:47:50 PM
Chapter 24: Asynchronous Partial Page Rendering
1197
Next, the _onFormSubmitCompleted method iterates through the objects in the arrayDeclarationNodes
array. Recall that each object in this array represents an array declaration for which the value of the
id
property of the object contains the name of the array being declared, and the value of the
content property
of the object contains the value being stored in the array. As you can see, the method takes the following
steps for each object in the
arrayDeclarationNodes array. First, it creates a string that contains a call into
the
_addArrayElement static method of the PageRequestManager class, passing in the values of the
id and content properties of the object as the arguments of the method. Next, it adds this string to
a local string named
arrayScript that accumulates all the strings associated with the objects in the

arrayDeclarationNodes array:
var arrayScript = ‘’;
for (i = 0; i < arrayDeclarationNodes.length; i++)
{
arrayScript += “Sys.WebForms.PageRequestManager._addArrayElement(‘” +
arrayDeclarationNodes[i].id + “’, “ +
arrayDeclarationNodes[i].content + “);\r\n”;
}
Next, the _onFormSubmitCompleted method iterates through the objects in the expandoNodes array.
Recall that each object in this array describes an
expando attribute for which the values of the id and


content properties of the object contain the name and value, respectively of the expando attribute. As
you can see, the
_onFormSubmitCompleted method forms a string for each object that consists of two
substrings separated by the equals sign, these substrings containing the name and value, respectively, of
the associated
expando attribute. Note that the expandoScript string accumulates all these strings.
var expandoScript = ‘’;
for (i = 0; i < expandoNodes.length; i++)
{
var propertyReference = expandoNodes[i].id;
var propertyValue = expandoNodes[i].content;
expandoScript += propertyReference + “ = “ + propertyValue + “\r\n”;
}
As you can see, the server response to an asynchronous page postback may contain scripts. The current
page may also contain scripts. Therefore, you need a way to avoid duplicate scripts. The ASP.NET AJAX
client-side framework comes with an internal class named
_ScriptLoader that provides the current

PageRequestManager instance with script-loading services. The _onFormSubmitCompleted method of
the current
PageRequestManager instance, shown in Listing 24-5 , uses these services to avoid loading
duplicate scripts as follows:
❑ The method begins by calling the readLoadedScripts static method on the _ScriptLoader
class. As you’ll see later, this static method populates an internal static collection named
_referencedScripts with the values of the src HTML attributes of all the script HTML
elements that currently exist on the current page. I say currently because the server response to
the current asynchronous page postback request may contain references to script files that the
existing script HTML elements on the current page may or may not reference.
Sys._ScriptLoader.readLoadedScripts();
c24.indd 1197c24.indd 1197 8/20/07 8:47:50 PM8/20/07 8:47:50 PM

Chapter 24: Asynchronous Partial Page Rendering
1198
❑ The method then calls the getInstance static method of the _ScriptLoader class to access the
current
_ScriptLoader instance. Each page can have only one instance of the _ScriptLoader
class. As you’ll see later, the
getInstance method checks whether an internal static field named

_instance references an instance of the _ScriptLoader class. If so, it simply returns this
reference. If not, it creates and returns a new instance of the
_ScriptLoader class and stores
this instance in this internal field for future use. This ensures that the current page always uses
the same instance of the
_ScriptLoader class.
var scriptLoader = Sys._ScriptLoader.getInstance();
❑ Next, the method calls the queueScriptBlock method on the current _ScriptLoader instance
to queue the script contained in the
arrayScript string. Recall that the arrayScript string
contains the script that declares one or more JavaScript arrays. The current page may or may not
contain the same ones.
❑ As you’ll see later, the queueScriptBlock method simply adds the specified script to an inter-
nal collection named
_scriptsToLoad :
if (arrayScript.length)
scriptLoader.queueScriptBlock(arrayScript);
❑ Next, the method calls the queueScriptBlock method on the current _ScriptLoader instance
to queue the script contained in the
expandoScript string. Recall that the expandoScript
string contains the script that defines one or more
expando attributes:

if (expandoScript.length)
scriptLoader.queueScriptBlock(expandoScript);
❑ Then the method iterates through the objects in the scriptBlockNodes array and takes the
following steps for each enumerated object:
❑ If the value of the id property of the object is the string “ScriptContentNoTags” , this
is an indication that the value of the
content property of the object contains a script
block. Therefore, the method calls the
queueScriptBlock method on the current
_ScriptLoader instance to queue this script block:
case “ScriptContentNoTags”:
scriptLoader.queueScriptBlock(scriptBlockNodes[i].content);
break;
❑ If the value of the id property of the object is the string “ScriptContentWithTags” , this
is an indication that the value of the
content property of the object does not contain a
script block. Instead it contains the JSON representation of the attributes of a script HTML
element. You can think of this JSON representation as the serialized form of these attri-
butes. It contains one name/value pair for each attribute, where the name part of the pair
is a string that contains the name of the attribute, and the value part is a string that con-
tains the value of the attribute. Keep in mind that some of these attributes may be custom
attributes.
c24.indd 1198c24.indd 1198 8/20/07 8:47:51 PM8/20/07 8:47:51 PM
Chapter 24: Asynchronous Partial Page Rendering
1199
❑ The _onFormSubmitCompleted method first checks whether this JSON representation
contains a name/value pair for the
src HTML attribute. If so, it uses the name part of this
pair — that is, the keyword
src — to access the value part of the pair — that is, the URL of

the referenced script file — and calls the
isScriptLoaded static method on the
_ScriptLoader class to check whether the internal _referencedScripts collection
contains an entry for this URL. (Recall that this collection contains the URLs of all the
currently referenced script files.) If so, the
_onFormSubmitCompleted method skips the
enumerated object. If not, it calls the
queueCustomScriptTag method on the current
_ScriptLoader instance, passing in the JSON representation of the script attributes. As
you’ll see later, this method simply adds this JSON representation to an internal collection
named
_scriptsToLoad . This collection contains one object for each script file that needs
to be loaded, and describes the HTML standard and custom script attributes.
case “ScriptContentWithTags”:
var scriptTagAttributes;
eval(“scriptTagAttributes = “ + scriptBlockNodes[i].content);
if (scriptTagAttributes.src &&
Sys._ScriptLoader.isScriptLoaded(scriptTagAttributes.src))
continue;
scriptLoader.queueCustomScriptTag(scriptTagAttributes);
break;
❑ If the value of the id property of the object is the string “ScriptPath” , this is an
indication that the value of the
content property of the object does not contain a script
block. Instead it contains the URL of a script file. The
_onFormSubmitCompleted method
first calls the
isScriptLoaded static method on the _ScriptLoader class to check
whether the internal
_referencedScripts collection contains an entry for this URL. If

so, it simply skips the enumerated object because the associated script has already
been loaded.
If not, it calls the queueScriptReference method on the current _ScriptLoader
instance, passing in the value of the
content property of the enumerated object — that is,
the URL. As you’ll see later, this method creates an object with a single name/value pair
and adds the object to the internal
_scriptsToLoad collection. The name part of this
name/value pair is the keyword
src and the value part is the URL.
❑ Keep in mind that _scriptsToLoad is a collection of objects in which each object
describes the HTML standard and custom script attributes associated with a particular
script file. To put it differently, this collection contains information about the script files
that need to be downloaded from the server.
case “ScriptPath”:
if (Sys._ScriptLoader.isScriptLoaded(scriptBlockNodes[i].content))
continue;
scriptLoader.queueScriptReference(scriptBlockNodes[i].content);
break;
❑ Next, the _onFormSubmitCompleted method iterates through the objects in the onSubmitNodes
array. Recall that each object in this array describes a dynamically added form
onsubmit state-
ment for which the value of the
id property of the object is an empty string and the value of the

content property is a string that contains the dynamically added form onsubmit statement.
c24.indd 1199c24.indd 1199 8/20/07 8:47:51 PM8/20/07 8:47:51 PM
Chapter 24: Asynchronous Partial Page Rendering
1200
❑ The _onFormSubmitCompleted method creates a local string named onSubmitStatementScript

that contains a script that adds a dynamically generated JavaScript function to the
_onSubmitStatements collection of the current PageRequestManager instance. Note that
the method iterates through the objects in the
onSubmitNodes collection and adds the value
of the
content property of each enumerated object to the body of this dynamically generated
JavaScript function.
var onSubmitStatementScript = ‘’;
for (var i = 0; i < onSubmitNodes.length; i++)
{
if (i === 0)
onSubmitStatementScript = ‘Array.add(Sys.WebForms.PageRequestManager
.getInstance()._onSubmitStatements, function() {\r\n’;
onSubmitStatementScript += onSubmitNodes[i].content + “\r\n”;
}
❑ Next, the method calls the queueScriptBlock method on the current _ScriptLoader instance
that is passing in the local
onSubmitStatementScript string. As you’ll see later, the

queueScriptBlock method creates a object with a single name/value pair and adds the object
to the internal
_scriptsToLoad collection of the current _ScriptLoader instance. The name
part of this name/value pair is the keyword
text and the value part contains the content of the

onSubmitStatementScript string.
if (onSubmitStatementScript.length)
{
onSubmitStatementScript += “\r\nreturn true;\r\n});\r\n”;
scriptLoader.queueScriptBlock(onSubmitStatementScript);

}
❑ Next, the _onFormSubmitCompleted method stores the reference to the WebRequestExecutor
object responsible for executing the current request in the
_response field of the current

PageRequestManager instance:
this._response = sender;
❑ Next, the _onFormSubmitCompleted method calls the createDelegate static method on the
function to create a delegate that represents the
_scriptsLoadComplete method of the current

PageRequestManager instance:
var scriptLoadCompleteDelegate = Function.createDelegate(this,
this._scriptsLoadComplete);
❑ Finally, the _onFormSubmitCompleted method calls the loadScripts method on the current
_ScriptLoader instance, passing in the delegate. As you’ll see later, this method will load the
scripts in the
_scriptsToLoad collection:
scriptLoader.loadScripts(0, scriptLoadCompleteDelegate, null, null);
c24.indd 1200c24.indd 1200 8/20/07 8:47:51 PM8/20/07 8:47:51 PM
Chapter 24: Asynchronous Partial Page Rendering
1201
Listing 24-5 : The _onFormSubmitCompleted Method of the PageRequestManager
function Sys$WebForms$PageRequestManager$_onFormSubmitCompleted(sender, eventArgs)
{
this._processingRequest = true;
var delimitByLengthDelimiter = ‘|’;

if (sender.get_timedOut())
{

this._endPostBack(this._createPageRequestManagerTimeoutError(), sender);
return;
}
if (sender.get_aborted())
{
this._endPostBack(null, sender);
return;
}
if (!this._request || sender.get_webRequest() !== this._request)
return;
var errorMessage;
var delta = [];
if (sender.get_statusCode() !== 200)
{
this._endPostBack(
this._createPageRequestManagerServerError(sender.get_statusCode()), sender);
return;
}
var reply = sender.get_responseData();
var delimiterIndex, len, type, id, content;
var replyIndex = 0;
var parserErrorDetails = null;
while (replyIndex < reply.length)
{
delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
if (delimiterIndex === -1)
{
parserErrorDetails = this._findText(reply, replyIndex);
break;
}


len = parseInt(reply.substring(replyIndex, delimiterIndex), 10);
if ((len % 1) !== 0)
{
parserErrorDetails = this._findText(reply, replyIndex);
break;
}
replyIndex = delimiterIndex + 1;
delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
(continued)
c24.indd 1201c24.indd 1201 8/20/07 8:47:51 PM8/20/07 8:47:51 PM
Chapter 24: Asynchronous Partial Page Rendering
1202
Listing 24-5 (continued)
if (delimiterIndex === -1)
{
parserErrorDetails = this._findText(reply, replyIndex);
break;
}
type = reply.substring(replyIndex, delimiterIndex);
replyIndex = delimiterIndex + 1;
delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
if (delimiterIndex === -1)
{
parserErrorDetails = this._findText(reply, replyIndex);
break;
}
id = reply.substring(replyIndex, delimiterIndex);
replyIndex = delimiterIndex + 1;
if ((replyIndex + len) >= reply.length)

{
parserErrorDetails = this._findText(reply, reply.length);
break;
}
content = this._decodeString(reply.substr(replyIndex, len));
replyIndex += len;
if (reply.charAt(replyIndex) !== delimitByLengthDelimiter)
{
parserErrorDetails = this._findText(reply, replyIndex);
break;
}
replyIndex++;
var obj = {type: type, id: id, content: content};
Array.add(delta, obj);
}
if (parserErrorDetails)
{
this._endPostBack(this._createPageRequestManagerParserError(
String.format(Sys.WebForms.Res.PRM_ParserErrorDetails,
parserErrorDetails)), sender);
return;
}
var updatePanelNodes = [];
var hiddenFieldNodes = [];
var arrayDeclarationNodes = [];
var scriptBlockNodes = [];
var expandoNodes = [];
var onSubmitNodes = [];
var dataItemNodes = [];
var dataItemJsonNodes = [];

var scriptDisposeNodes = [];
var asyncPostBackControlIDsNode, postBackControlIDsNode,
updatePanelIDsNode, asyncPostBackTimeoutNode,
childUpdatePanelIDsNode, panelsToRefreshNode, formActionNode;
c24.indd 1202c24.indd 1202 8/20/07 8:47:52 PM8/20/07 8:47:52 PM
Chapter 24: Asynchronous Partial Page Rendering
1203
for (var i = 0; i < delta.length; i++)
{
var deltaNode = delta[i];
switch (deltaNode.type)
{
case “updatePanel”:
Array.add(updatePanelNodes, deltaNode);
break;
case “hiddenField”:
Array.add(hiddenFieldNodes, deltaNode);
break;
case “arrayDeclaration”:
Array.add(arrayDeclarationNodes, deltaNode);
break;
case “scriptBlock”:
Array.add(scriptBlockNodes, deltaNode);
break;
case “expando”:
Array.add(expandoNodes, deltaNode);
break;
case “onSubmit”:
Array.add(onSubmitNodes, deltaNode);
break;

case “asyncPostBackControlIDs”:
asyncPostBackControlIDsNode = deltaNode;
break;
case “postBackControlIDs”:
postBackControlIDsNode = deltaNode;
break;
case “updatePanelIDs”:
updatePanelIDsNode = deltaNode;
break;
case “asyncPostBackTimeout”:
asyncPostBackTimeoutNode = deltaNode;
break;
case “childUpdatePanelIDs”:
childUpdatePanelIDsNode = deltaNode;
break;
case “panelsToRefreshIDs”:
panelsToRefreshNode = deltaNode;
break;
case “formAction”:
formActionNode = deltaNode;
break;
case “dataItem”:
Array.add(dataItemNodes, deltaNode);
break;
case “dataItemJson”:
Array.add(dataItemJsonNodes, deltaNode);
break;
case “scriptDispose”:
Array.add(scriptDisposeNodes, deltaNode);
break;

(continued)
c24.indd 1203c24.indd 1203 8/20/07 8:47:52 PM8/20/07 8:47:52 PM

×