Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 96 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
96
Dung lượng
625,95 KB
Nội dung
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 [...]... } 1212 c24.indd 1212 8/20/07 8:47:55 PM Chapter 24: Asynchronous Partial Page Rendering _getLoadedScript As Listing 2 4-1 4 shows, the _getLoadedScripts static method of the _ScriptLoader class simply returns a reference to the _referencedScripts collection, which contains the values of the src HTML attributes of all the script HTML elements that currently exist on the current page Listing 2 4-1 4: The... _ScriptLoader class As Listing 2 4-9 shows, the readLoadedScripts method first instantiates the _referencedScripts static field of the class: 1210 c24.indd 1210 8/20/07 8:47:54 PM Chapter 24: Asynchronous Partial Page Rendering Sys._ScriptLoader._referencedScripts = []; Next, it calls the getElementByTagName method on the document object to return an array that contains references to all the script HTML... if(!Sys._ScriptLoader._referencedScripts) { Sys._ScriptLoader._referencedScripts = []; Sys._ScriptLoader.readLoadedScripts(); } return Sys._ScriptLoader._referencedScripts; } queueScriptReference Recall from Listing 2 4-5 that the _onFormSubmitCompleted method of the current client script PageRequestManager instance calls the queueScriptReference method on the current _ScriptLoader instance to queue the specified script reference. .. - 1; i >= 0; i ) { if (existingScripts[i].src.length) { if (!Array.contains(Sys._ScriptLoader._referencedScripts, existingScripts[i].src)) Array.add(Sys._ScriptLoader._referencedScripts, existingScripts[i].src); } } } } getInstance As Listing 2 4-1 0 shows, the getInstance static method of the _ScriptLoader class ensures that each page can have only one instance of the _ScriptLoader class Listing 2 4-1 0:... hierarchy that has the specified root DOM element The _destroyTree method takes a reference to a DOM element and deletes it and all its descendant DOM elements As Listing 2 4-8 shows, this method first makes sure that its argument is indeed an element Then it iterates through the child DOM 1209 c24.indd 1209 8/20/07 8:47:54 PM Chapter 24: Asynchronous Partial Page Rendering elements of the element and takes... scriptAttributes); } isScriptLoaded Recall from Listing 2 4-5 that the _onFormSubmitCompleted method of the current PageRequestManager instance invokes the isScriptLoaded static method on the _ScriptLoader class to determine whether the script file with the specified URL has already been loaded Listing 2 4-1 3 presents the implementation of this method Listing 2 4-1 3: The isScriptLoaded Static Method of the _ScriptLoader... Sys$_ScriptLoader$queueScriptReference(scriptUrl) { if(!this._scriptsToLoad) this._scriptsToLoad = []; Array.add(this._scriptsToLoad, {src: scriptUrl}); } loadScripts Recall from Listing 2 4-5 that the _onFormSubmitCompleted method of the current client-side PageRequestManager instance calls the loadScripts method on the current _ScriptLoader instance to load the scripts in the _scriptsToLoad collection As Listing 2 4-1 6 shows,... this._scriptDisposes[updatePanelID]; } } this._destroyTree(updatePanelElement); updatePanelElement.innerHTML = rendering; } 1208 c24.indd 1208 8/20/07 8:47:53 PM Chapter 24: Asynchronous Partial Page Rendering The registerDisposeScript Method of PageRequestManager Recall from Listing 2 4-5 that the _onFormSubmitCompleted method of the current PageRequestManager instance iterates through a local collection named... instance, passing in a reference to the current PageRequestManager instance and the PageLoadingEventArgs object: handler(this, args); 1194 c24.indd 1194 8/20/07 8:47:49 PM Chapter 24: Asynchronous Partial Page Rendering 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... j = behaviors.length - 1; j >= 0; j ) { behaviors[j].dispose(); } this._destroyTree(node); } } } } _ScriptLoader The main responsibility of the _ScriptLoader class is to load the required scripts As you saw, Listing 2 4-5 makes extensive use of this class In this section, I’ll walk you though the implementation of the methods of the class readLoadedScripts Recall from Listing 2 4-5 that the _onSubmitFormCompleted . 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 2 4-1 : The _onFormSubmit Method of the Client-Side PageRequestManager. (hiddenField) PageRequestManager (Processing Server Response) - Second Part Figure 2 4-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,. in the highlighted portion of Listing 2 4-3 . Listing 2 4-3 : The Completed Method function Sys $Net$ WebRequest$completed(eventArgs) { var handler = Sys .Net. WebRequestManager._get_eventHandlerList().getHandler(