ptg 1714 CHAPTER 38 Using Server-Side ASP.NET AJAX var prm = Sys.WebForms.PageRequestManager.getInstance(); prm.add_pageLoaded( prm_pageLoaded ); function prm_pageLoaded(sender, args) { if (prm.get_isInAsyncPostBack()) { var movieTitle = args.get_dataItems()[‘Head1’]; // assign browser title bar document.title = movieTitle; // assign heading $get(‘hTitle’).innerHTML = movieTitle; } } </script> </body> </html> When you navigate to a new movie, both the browser title bar, and the page heading are updated to display the title of the new movie (see Figure 38.12). The title and heading are updated by passing a data item that represents the movie title during the asynchronous postback. FIGURE 38.12 Updating a page’s header and title asynchronously. Handling UpdatePanel Errors Gracefully Sometimes things go terribly wrong. The Internet gets clogged, an application’s database server goes down, and so on. How do you recover from these types of errors gracefully in an Ajax application? From the Library of Wow! eBook ptg 1715 Using the UpdatePanel Control 38 By default, if an error occurs during an asynchronous postback, a JavaScript alert box appears that displays an error message. This is a jarring experience in a production application. You have several options for avoiding this default experience: You can configure a custom error page; you can handle the error on the server side; or you can handle the error on the client side. Let’s examine each of these options. First, if you configure a custom error page for your application, by default the custom error page applies to asynchronous postback errors. You enable a custom error page by adding the following element to the system.web section of your web configuration file: <customErrors mode=”On” defaultRedirect=”ErrorPage.aspx” /> This element enables a custom error page for both local and remote requests. Any unhan- dled exceptions in any page cause the browser to be redirected to a page named ErrorPage.aspx. The page in Listing 38.17 throws an exception when you click the button located in the UpdatePanel control. If you open the page in Listing 38.17 with a custom error page enabled, the browser is redirected to the ErrorPage.aspx page automatically. LISTING 38.17 UpdatePanelError.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void btnSubmit_Click(object sender, EventArgs e) { throw new Exception(“Server Error”); } </script> <html xmlns=”http://www.w3.org/1999/xhtml”> <head runat=”server”> <title>UpdatePanel Error</title> </head> <body> <form id=”form1” runat=”server”> <asp:ScriptManager id=”sm1” Runat=”server” /> <asp:UpdatePanel id=”up1” runat=”server”> From the Library of Wow! eBook ptg 1716 CHAPTER 38 Using Server-Side ASP.NET AJAX <ContentTemplate> <asp:Button id=”btnSubmit” Text=”Submit” OnClick=”btnSubmit_Click” Runat=”server” /> </ContentTemplate> </asp:UpdatePanel> </form> </body> </html> You can disable custom error pages in the case of an asynchronous postback by adding an AllowCustomErrorRedirect attribute to the ScriptManager tag, like this: <asp:ScriptManager id=”sm1” AllowCustomErrorsRedirect=”false” Runat=”server” /> Instead of redirecting the user to an error page, you can customize the error message that the user sees. You can customize the error on both the server and the client. On the server, you can handle the ScriptManager control’s AsyncPostBackError event to customize the error message transmitted to the client. For example, the page in Listing 38.18 modifies the error message to be a generic one. LISTING 38.18 UpdatePanelErrorServer.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void btnSubmit_Click(object sender, EventArgs e) { throw new Exception(“Server Error”); } protected void sm1_AsyncPostBackError(object sender, ➥ AsyncPostBackErrorEventArgs e) From the Library of Wow! eBook ptg 1717 Using the UpdatePanel Control 38 { sm1.AsyncPostBackErrorMessage = “A server error occurred”; } </script> <html xmlns=”http://www.w3.org/1999/xhtml”> <head id=”Head1” runat=”server”> <title>UpdatePanel Error Server</title> </head> <body> <form id=”form1” runat=”server”> <asp:ScriptManager id=”sm1” OnAsyncPostBackError=”sm1_AsyncPostBackError” Runat=”server” /> <asp:UpdatePanel id=”up1” runat=”server”> <ContentTemplate> <asp:Button id=”btnSubmit” Text=”Submit” OnClick=”btnSubmit_Click” Runat=”server” /> </ContentTemplate> </asp:UpdatePanel> </form> </body> </html> The page in Listing 38.18 cloaks the actual server-side error message with a generic message. The error message displayed by the page is still not professional. Most likely, you’ll want to customize the error message even more when the error is displayed on the client. The page in Listing 38.19 illustrates how UpdatePanelErrorServer.aspx you can customize an error message on the client. The page displays an error message directly above the UpdatePanel when an asynchronous postback fails (see Figure 38.13). From the Library of Wow! eBook ptg 1718 CHAPTER 38 Using Server-Side ASP.NET AJAX LISTING 38.19 UpdatePanelErrorClient.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void btnSubmit_Click(object sender, EventArgs e) { throw new Exception(“Server Error”); } protected void sm1_AsyncPostBackError(object sender, ➥ AsyncPostBackErrorEventArgs e) { sm1.AsyncPostBackErrorMessage = “A server error occurred”; } </script> <html xmlns=”http://www.w3.org/1999/xhtml”> <head id=”Head1” runat=”server”> <title>UpdatePanel Error Server</title> <style type=”text/css”> .errorMessage { background-color: Yellow; color: Red; } </style> </head> <body> FIGURE 38.13 Customizing a client-side error message. From the Library of Wow! eBook ptg 1719 Using the UpdatePanel Control 38 <form id=”form1” runat=”server”> <asp:ScriptManager id=”sm1” OnAsyncPostBackError=”sm1_AsyncPostBackError” Runat=”server” /> <span id=”spanError” class=”errorMessage”></span> <asp:UpdatePanel id=”up1” runat=”server”> <ContentTemplate> <asp:Button id=”btnSubmit” Text=”Submit” OnClick=”btnSubmit_Click” Runat=”server” /> </ContentTemplate> </asp:UpdatePanel> </form> <script type=”text/javascript”> var prm = Sys.WebForms.PageRequestManager.getInstance(); prm.add_endRequest( prm_endRequest ); function prm_endRequest(sender, args) { var spanError = $get(“spanError”); if (args.get_error()) { args.set_errorHandled(true); spanError.innerHTML = “Could not complete your request”; } else { spanError.innerHTML = ““; } } </script> </body> </html> From the Library of Wow! eBook ptg 1720 CHAPTER 38 Using Server-Side ASP.NET AJAX Before leaving this section, I need to mention one last property supported by the ScriptManager control related to errors: AsyncPostBackTimeOut. This property determines the amount of time in seconds before an asynchronous postback times out. The default value is 90 seconds. You might want to set this value to a briefer duration. UpdatePanel Performance The UpdatePanel hides the normal page postback by performing an asynchronous (sneaky) postback. Even though you can use the UpdatePanel to trick your users into believing that a postback is not occurring, it is important that you do not trick yourself. You can use either of the two debugging tools discussed earlier in this chapter to view the Ajax request and response that occur during an asynchronous postback. For example, Listing 38.20 contains a typical Ajax request, and Listing 38.21 contains a typical Ajax response. LISTING 38.20 Ajax Request sm1=up1%7CgrdFeedback&__EVENTTARGET=grdFeedback&__EVENTARGUMENT=Sort%24Name&__VIEWS TATE=%2FwEPDwUKLTk4MzMyODc2MQ9kFgICAw9kFgICAw9kFgJmD2QWBAIBDzwrAAoBAA8WBB4LXyFEYXRh Qm91bmRnHgtfIUl0ZW1Db3VudGZkFgJmD2QWBGYPDxYCHgdWaXNpYmxlaGRkAgIPDxYCHwJoZGQCAw88KwA NAgAPFgQfAGcfAQIEZAwUKwAEFggeBE5hbWUFAklkHgpJc1JlYWRPbmx5aB4EVHlwZRkrAR4JRGF0YUZpZW xkBQJJZBYIHwMFBE5hbWUfBGgfBRkrAh8GBQROYW1lFggfAwUHQ29tbWVudB8EaB8FGSsCHwYFB0NvbW1lb nQWCB8DBQ1EYXRlU3VibWl0dGVkHwRoHwUZKVxTeXN0ZW0uRGF0ZVRpbWUsIG1zY29ybGliLCBWZXJzaW9u PTIuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OR8GBQ1 EYXRlU3VibWl0dGVkFgJmD2QWCgIBD2QWCGYPDxYCHgRUZXh0BQE0ZGQCAQ8PFgIfBwUFU3RldmVkZA- ICDw8WAh8HBRJIZXJlIGlzIG15IGNvbW1lbnRkZAIDDw8WAh8HBRQxMC8zLzIwMDcgNDo1MjowNCBQTWRk- AgIPZBYIZg8PFgIfBwUBM2RkAgEPDxYCHwcFA0JvYmRkAgIPDxYCHwcFFUhleSwgd2hhdCBhYm91dCBBamF 4P2RkAgMPDxYCHwcFFDEwLzMvMjAwNyA0OjE5OjI1IFBNZGQCAw9kFghmDw8WAh8HBQExZGQCAQ8PFgIfB- wUFc3RldmVkZAICDw8WAh8HBRVXaGF0IGEgZ3JlYXQgd2Vic2l0ZSFkZAIDDw8WAh8HBRQxMC8zLzIwMD- cgNDowOTo1NiBQTWRkAgQPZBYIZg8PFgIfBwUBMmRkAgEPDxYCHwcFBXN0ZXZlZGQCAg8PFgIfBwVaV293L CBpdCBpcyB3cml0dGVuIGVudGlyZWx5IHdpdGggTGlucT8gVGhhdCBtdXN0IGhhdmUgc2F2ZWQgeW91IGEg bG90IG9mIGRldmVsb3BtZW50IHRpbWUhZGQCAw8PFgIfBwUUMTAvMy8yMDA3IDQ6MDk6NTYgUE1kZA- IFDw8WAh8CaGRkGAIFC2dyZEZlZWRiYWNrDzwrAAkCBAUHQ29tbWVudAgCAWQFC2ZybUZlZWRiYWNrDx- QrAAdkZAICZGQWAGRkuZs7yL%2Fem%2BLQG%2FRqUcYBa9aTsI4%3D&frmFeedback%24txtName=&frmFe edback%24txtComment=&__EVENTVALIDATION=%2FwEWCALS%2BMLfAgKVvojNBgKio6JkAp7t150BAtnw 1uUHApCu1%2B4GAoKl7PcLAoGY7eABIj9XtltK55e8Og9%2BNK4DglwM43M%3D& LISTING 38.21 Ajax Response 2124|updatePanel|up1| <table cellspacing=”0” border=”0” id=”frmFeedback” style=”border-collapse:collapse;”> <tr> From the Library of Wow! eBook ptg 1721 Using the UpdatePanel Control 38 <td colspan=”2”> <label for=”frmFeedback_txtName” id=”frmFeedback_lblName”>Name:</label> <span id=”frmFeedback_valName” style=”color:Red;visibility:hidden;”> ➥ Required</span> <br /> <input name=”frmFeedback$txtName” type=”text” id=”frmFeedback_txtName” /> <br /><br /> <label for=”frmFeedback_txtComment” id=”frmFeedback_lblComment”> ➥ Comment:</label> <span id=”frmFeedback_valComment” style=”color:Red;visibility:hidden;”> ➥ Required</span> <br /> <textarea name=”frmFeedback$txtComment” rows=”3” cols=”50” id=”frmFeedback_txtComment”></textarea> <br /><br /> <input type=”submit” name=”frmFeedback$btnSubmit” value=”Submit” onclick=”javascript:WebForm_DoPostBackWithOptions (new WebForm_PostBackOptions("frmFeedback$btnSubmit", "", true, "", "", false, false))” id=”frmFeedback_btnSubmit” /> </td> </tr> </table> <br /><br /> <div> <table cellspacing=”0” rules=”all” border=”1” id=”grdFeedback” style=”border-collapse:collapse;”> <tr> <th scope=”col”><a href=”javascript:__ doPostBack(‘grdFeedback’,’Sort$Id’)”>Id</a></th> <th scope=”col”><a href=”javascript:__doPostBack (‘grdFeedback’,’Sort$Name’)”>Name</a></th><th ➥ scope=”col”> <a href=”javascript:__doPostBack (‘grdFeedback’,’Sort$Comment’)”>Comment</a></th> <th scope=”col”><a href=”javascript:__doPostBack (‘grdFeedback’,’Sort$DateSubmitted’)”> DateSubmitted</a></th> </tr><tr> <td>3</td><td>Bob</td><td>Hey, what about Ajax? </td><td>10/3/2007 4:19:25 PM</td> </tr><tr> <td>1</td><td>steve</td><td>What a great website! From the Library of Wow! eBook ptg 1722 CHAPTER 38 Using Server-Side ASP.NET AJAX </td><td>10/3/2007 4:09:56 PM</td> </tr><tr> <td>2</td><td>steve</td><td>Wow, it is written entirely with Linq? That must have saved you a lot of development time!</td><td>10/3/2007 4:09:56 PM</td> </tr><tr> <td>4</td><td>Steve</td><td>Here is my comment </td><td>10/3/2007 4:52:04 PM</td> </tr> </table> </div> |0|hiddenField|__EVENTTARGET||0|hiddenField|__EVENTARGUMENT||1264|hidden- Field|__VIEWSTATE|/wEPDwUKLTk4MzMyODc2MQ9kFgICAw9kFgICAw9kFgJmD2QWBAIBDzwrAAoBAA8WB B4LXyFEYXRhQm91bmRnHgtfIUl0ZW1Db3VudGZkFgJmD2QWBGYPDxYCHgdWaXNpYmxlaGRkAgIPDxYCH- wJoZGQCAw88KwANAgAPFgQfAGcfAQIEZAwUKwAEFggeBE5hbWUFAklkHgpJc1JlYWRPbmx5aB4EVHlwZRkr AR4JRGF0YUZpZWxkBQJJZBYIHwMFBE5hbWUfBGgfBRkrAh8GBQROYW1lFggfAwUHQ29tbWVudB8EaB8FGSs CHwYFB0NvbW1lbnQWCB8DBQ1EYXRlU3VibWl0dGVkHwRoHwUZKVxTeXN0ZW0uRGF0ZVRpbWUsIG1zY29ybG liLCBWZXJzaW9uPTIuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYx- OTM0ZTA4OR8GBQ1EYXRlU3VibWl0dGVkFgJmD2QWCgIBD2QWCGYPDxYCHgRUZXh0BQEzZGQCAQ8PFgIfB- wUDQm9iZGQCAg8PFgIfBwUVSGV5LCB3aGF0IGFib3V0IEFqYXg/ZGQCAw8PFgIfBwUUMTAvMy8yMDA3IDQ6 MTk6MjUgUE1kZAICD2QWCGYPDxYCHwcFATFkZAIBDw8WAh8HBQVzdGV2ZWRkAgIPDxYCHwcFFVdoYXQgYS- BncmVhdCB3ZWJzaXRlIWRkAgMPDxYCHwcFFDEwLzMvMjAwNyA0OjA5OjU2IFBNZGQCAw9kFghmDw8WAh8HB QEyZGQCAQ8PFgIfBwUFc3RldmVkZAICDw8WAh8HBVpXb3csIGl0IGlzIHdyaXR0ZW4gZW50aXJlbHkgd2l0 aCBMaW5xPyBUaGF0IG11c3QgaGF2ZSBzYXZlZCB5b3UgYSBsb3Qgb2YgZGV2ZWxvcG1lbnQgdGltZS- FkZAIDDw8WAh8HBRQxMC8zLzIwMDcgNDowOTo1NiBQTWRkAgQPZBYIZg8PFgIfBwUBNGRkAgEPDxYCHwcF- BVN0ZXZlZGQCAg8PFgIfBwUSSGVyZSBpcyBteSBjb21tZW50ZGQCAw8PFgIfBwUUMTAvMy8yMDA3IDQ6NTI 6MDQgUE1kZAIFDw8WAh8CaGRkGAIFC2dyZEZlZWRiYWNrDzwrAAkCBAUETmFtZQgCAWQFC2ZybUZlZWRiY- WNrDxQrAAdkZAICZGQWAGRkVKO/p/Z+TKr7wPvuagKWmQ2FfIY=|96|hiddenField|__EVENTVALIDA- TION|/wEWCAKuyYyNBQKVvojNBgKio6JkAp7t150BAtnw1uUHApCu1+4GAoKl7PcLAoGY7eABqkyic8N4ML Im8nwM1bpWblCsXyA=|0|asyncPostBackControlIDs|||0|postBackControlIDs|||4|updatePan- elIDs||tup1|0|childUpdatePanelIDs|||3|panelsToRefreshIDs||up1|2|asyncPostBackTime- out||90|13|formAction||Feedback.aspx|8|pageTitle||Feedback|46|arrayDeclaration|Page _Validators|document.getElementById(“frmFeedback_valName”)|49|arrayDeclaration|Page _Validators|document.getElementById(“frmFeedback_valComment”)|139|scriptBlock|Scrip tPath|/Original/ScriptResource.axd?d=pGcnA3xf7SUaukdr- behbvslg2hOq48wA9WuXk0fdM20k9xho9i9m9JZzVPbP2- 5l3cHqVSeROczjHZXGFjpag2&t=633231592768281250|367|scriptBlock|ScriptContentWithTags |{“text”:”\r\n\u003c!—\r\nvar Page_ValidationActive = false;\r\nif (typeof(Valida- torOnLoad) == \”function\”) {\r\n ValidatorOnLoad();\r\n}\r\n\r\nfunction Val- idatorOnSubmit() {\r\n if (Page_ValidationActive) {\r\n return ValidatorCommonOnSubmit();\r\n }\r\n else {\r\n return true;\r\n }\r\n}\r\n// —\u003e\r\n”,”type”:”text/javascript”}|90|onSubmit||if (typeof(Val- idatorOnSubmit) == “function” && ValidatorOnSubmit() == false) return false;|21|expando|document.getElementById(‘frmFeedback_valName’)[‘controltovali- date’]|”frmFeedback_txtName”|39|expando|document.getElementById(‘frmFeedback_val- From the Library of Wow! eBook ptg 1723 Using the UpdatePanel Control 38 Name’)[‘evaluationfunction’]|”RequiredFieldValidatorEvaluateIsValid”|2|expando|doc- ument.getElementById(‘frmFeedback_valName’)[‘initialvalue’]|””|24|expando|docu- ment.getElementById(‘frmFeedback_valComment’)[‘controltovalidate’]|”frmFeedback_txt Comment”|39|expando|document.getElementById(‘frmFeedback_valComment’)[‘evaluation- function’]|”RequiredFieldValidatorEvaluateIsValid”|2|expando|document.getElement- ById(‘frmFeedback_valComment’)[‘initialvalue’]|””|78|scriptDispose|up1|Array.remove (Page_Validators, document.getElementById(‘frmFeedback_valName’));|81|scriptDis- pose|up1|Array.remove(Page_Validators, document.getElementById(‘frmFeedback_valCom- ment’));| The Ajax request and response in Listing 38.20 and Listing 38.21, respectively, were captured using Fiddler after sorting by the Name column in the Feedback.aspx page. I’m including the full request and response traffic to make a point. No one would describe either the request or response as tiny. A lot of text must be passed back and forth from the browser to the server and back again when an UpdatePanel control refreshes its content. A big chunk of both the request and response consists of ViewState, which is passed to the server during an asynchronous postback, just like it is passed during a normal post- back. The server-side page executes just like it executes during a normal postback. Therefore, the server-side page needs the ViewState to execute correctly. To improve the performance of asynchronous postbacks performed by an UpdatePanel, consider disabling ViewState for the controls contained within the UpdatePanel. Every ASP.NET control has an EnableViewState property. You can always set this property to the value False to disable ViewState. The following table compares the size of the asynchronous request and response with the GridView control’s ViewState enabled and disabled: Ajax Request/Response Size ViewState Enabled ViewState Disabled Request 2,066 1,067 Response 5,720 4,719 As the table clarifies, you save about 1,000 bytes for both the request and response by disabling ViewState. The disadvantage of disabling ViewState for a control such as a GridView is that it forces GridView to make a new database call whenever you sort or page GridView. However, one easy way to reduce the load on your database server is to take advantage of caching. If you cache all the records displayed by GridView on the server, and disable ViewState; then you reduce your network traffic and you don’t place any additional load on your database server. From the Library of Wow! eBook . Im8nwM1bpWblCsXyA=|0|asyncPostBackControlIDs|||0|postBackControlIDs|| |4| updatePan- elIDs||tup1|0|childUpdatePanelIDs|||3|panelsToRefreshIDs||up1|2|asyncPostBackTime- out||90|13|formAction||Feedback.aspx|8|pageTitle||Feedback |46 |arrayDeclaration|Page. ptg 17 14 CHAPTER 38 Using Server-Side ASP. NET AJAX var prm = Sys.WebForms.PageRequestManager.getInstance(); prm.add_pageLoaded( prm_pageLoaded ); function prm_pageLoaded(sender,. Library of Wow! eBook ptg 1718 CHAPTER 38 Using Server-Side ASP. NET AJAX LISTING 38.19 UpdatePanelErrorClient.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC -/ /W3C//DTD XHTML 1.0