By default, if an error occurs during an asynchronous postback, a JavaScript alert box appears that displays an error message.. You have several options for avoiding this default experie
Trang 1var 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?
Trang 2By 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”>
Trang 3<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)
Trang 4{
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)
Trang 5LISTING 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
Trang 6<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>
Trang 7Before 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>
Trang 8<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!
Trang 9</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-
Trang 10
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 postpost-back
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
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