Kevin Grohoske

Director of Software Development

Posted on August 26, 2008

Creating and Displaying Dynamic Serverside Error Messages with MS Ajax

Thank you Keith Brooks for contributing to this article.

If you have ever tried to capture exceptions in your codebehind and display friendly messges the users using Microsoft’s AJAX toolkit, you may find the very simple idea becomes complicated very quickly. I ran into this when I had some projects that I wanted to AJAX’ify by using a typical alert method that registered a block of client side javascript and was fired on the pages Load event, but found that method failed when using AJAX.

Let me explain why… when a normal ASP.NET page renders it goes through a typical a Page Life Cycle . For normal page lifecycle, the script blocks are written to the client during the Initialization event and once complete the Load event code executes.

However, with a ASP.NET AJAX that page life cycle is somewhat different. On the initial page load, the page loads using the standard ASP.NET Page Lifecycle; however, when posting data back to the server using an AJAX update panel not all of the page is being sent back to the server, hence the AJAX. Because of this when the AJAX post to the server is complete, the entire page is not re-rendered. Only the contents of the update panel is updated and no page level Load event fires.

Here lies the issue. Since the page does not completely re-render and there is no client side Page Load event after the postback, many of the old scripts for displaying error messages do not work.

Ok. Enough of the lecture. You probably want to learn the solution.

There are a few parts to this solution. First, the ScriptManager object has a relatively obscure property called “onasyncpostbackerror”. This property represents the code behind function (server side) that gets fired when an exception happens during a post back. So the first step is to register a function using this property.

<asp id="ScriptManager1" runat="server" onasyncpostbackerror="ScriptManager1_AsyncPostBackError"></asp>

Next step is to write the code behind’s AsyncPostBack error method. In my case, I had already handled the exception, wrapped it, and threw the user friendly exception, therefore this was all I needed in my code behind. Realize that you must raise the exception and leave it unhandled for it to bubble up to the Script Manager’s event to handle it.

protected void ScriptManager1_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)
{
ScriptManager1.AsyncPostBackErrorMessage = e.Exception.Message;
}

Here is a simple demonstration of how I set up forced the exception.

protected void Button1_Click(object sender, EventArgs e)
{
try
{
DoingSomething();
}
catch (Exception ex)
{
throw new Exception("The system has encountered problems, please notify your administrator or try again.", ex);
}
}
private void DoingSomething()
{
throw new Exception("inner exception message");
}

Now back to the client side of the example. I have to register an event in javascript to handle the ‘EndRequestHandler’ event created by the AJAX post back. This event fires upon the return on the post back to the client and I also added some features to remove the default exception, “Sys.WebForms.PageRequestManagerServerErrorException:”, and I’m displaying the Exception using a Panel control and the ModalPopupExtender (shown below) using the MS AJAX ModalPopupExtender object.

Sys.WebForms.PageRequestManager.getInstance().
add_endRequest(EndRequestHandler);
function EndRequestHandler(sender, args)
{
if (args.get_error() != undefined && args.get_error().httpStatusCode == '500')
{
var errorMessage = args.get_error().message
errorMessage = errorMessage.replace('Sys.WebForms.
PageRequestManagerServerErrorException:', "");
args.set_errorHandled(true);
$get("txtAlertMessage").innerHTML = errorMessage;
$find("ModalAlertDialogBehavior").show();
}
}

Here is the source of the Panel I use and the ModalPopupExtender:

{Note: for the the modal dialog extender you need to bind the control to a button, but that button may be hidden, as you will see in my source code. I call the Show() method of the Modal Dialog’s Behavior. You do not call show on the modal dialog object itself.}

<asp:Panel ID="AlertPanel" runat="server" CssClass="modalPopup">
<asp:Panel ID="AlertPanelContent" runat="server" >
<table class="AlertTable">
<tr class="AlertRow" height="20px">
<td class="AlertTitle" height="20px">
<center>
<asp:Label ID="lblAlertTitle" runat="server" Text="Label" height="20px"/>
</center>
</td>
</tr>
<tr class="AlertRow">
<td>
<div id="txtAlertMessage" class="AlertTextMessage" />
</td>
</tr>
<tr class="AlertRow">
<td>
<center>
<asp:Button ID="btnClose" runat="server" Text="Close" />
</center>
</td>
</tr>
</table>
</asp:Panel>
</asp:Panel>
<ajaxToolkit:ModalPopupExtender ID="ModalAlertDialog" runat="server" BackgroundCssClass="modalBackground" TargetControlID="NullButton" PopupControlID="AlertPanel" CancelControlID="btnClose" BehaviorID="ModalAlertDialogBehavior" DropShadow="false" />
<asp:Button ID="NullButton" runat="server" Text="" CssClass="AlertNullButton" />

{Note: you will need the css file for the ModalPopupExtender to display correctly. }

Putting all the pieces together:

The button click event calls the ‘DoSomething’ method. The DoSomething method throw an exception . The try catch block in the button click event catches the exception and wraps it in an outer Exception which contains a user friendly message. The ‘AsyncPostBackError’ method passes back the exceptions message and the client side EndRequestHandler checks for the exception and displays the message.

Here is my entire ASP.NET page code:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AlertExample._Default" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<link href="Includes/Stylesheet1.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" onasyncpostbackerror="ScriptManager1_AsyncPostBackError" >
</asp:ScriptManager>
<div>
<script type="text/javascript" language="javascript">
Sys.WebForms.PageRequestManager.getInstance().
add_endRequest(EndRequestHandler);
function EndRequestHandler(sender, args)
{
if (args.get_error() != undefined && args.get_error().httpStatusCode == '500')
{
var errorMessage = args.get_error().message
errorMessage = errorMessage.replace('Sys.WebForms.
PageRequestManagerServerErrorException:', "");
args.set_errorHandled(true);
$get("txtAlertMessage").innerHTML = errorMessage;
$find("ModalAlertDialogBehavior").show();
}
}
</script>
</div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" > <ContentTemplate>
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:Panel ID="AlertPanel" runat="server" CssClass="modalPopup">
<asp:Panel ID="AlertPanelContent" runat="server" >
<table class="AlertTable">
<tr class="AlertRow" height="20px">
<td class="AlertTitle" height="20px">
<center><asp:Label ID="lblAlertTitle" runat="server" Text="Label" height="20px"/>
</center>
</td>
</tr>
<tr class="AlertRow">
<td>
<div id="txtAlertMessage" class="AlertTextMessage" />
</td>
</tr>
<tr class="AlertRow">
<td>
<center>
<asp:Button ID="btnClose" runat="server" Text="Close" />
</center>
</td>
</tr>
</table>
</asp:Panel>
</asp:Panel>
<ajaxToolkit:ModalPopupExtender ID="ModalAlertDialog" runat="server" BackgroundCssClass="modalBackground" TargetControlID="NullButton" PopupControlID="AlertPanel" CancelControlID="btnClose" BehaviorID="ModalAlertDialogBehavior" DropShadow="false" />
<asp:Button ID="NullButton" runat="server" Text="" CssClass="AlertNullButton" />
</form>
</body>
</html>

And here is my entire codebehind class:

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
namespace AlertExample
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
lblAlertTitle.Text = "Alert Example";
}
protected void Button1_Click(object sender, EventArgs e)
{
try
{
DoingSomething();
}
catch (Exception ex)
{
throw new Exception("The system has encountered problems, please notify your administrator or try again.", ex);
}
}
private void DoingSomething()
{
throw new Exception("inner exception message");
}
protected void ScriptManager1_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)
{
ScriptManager1.AsyncPostBackErrorMessage = e.Exception.Message;
}
}
}

And finally the entire CSS:

/*Popup Control*/
/*Modal Popup*/
.modalBackground {
background-color:Gray;
filter:alpha(opacity=70);
opacity:0.7;
}
.modalPopup {
background-color:#FFF;
border-width:1px;
border-style:solid;
border-color:ActiveCaption;
padding:0px;
width:400px;
height:260px;
vertical-align:middle;
}
.AlertOkButton
{
text-align:center;
}
.AlertTable
{
width:100%;
height:100%;
border-spacing:0px;
margin-left:0px;
margin-right:0px;
padding:0px;
}
.AlertRow
{
padding:2px;
}
.AlertTitle
{
background-image:url('../includes/Office2003BlueBG.png');
background-repeat:repeat-x;
background-color:ActiveCaption;
color:White;
font-weight:bold;
width:100%;
height:21px;
max-height:21px;
}
.AlertRow
{
padding:2px;
}
.AlertTextMessage
{
width:350px;
min-height:180px;
max-height:180px;
color:Black;
background-color:#FFF;
padding:0px;
border-spacing:0px;
margin-left:20px;
margin-top:20px;
}
.AlertNullButton
{
visibility:hidden;
}

Sample output of the AJAX Modial Dialog Example

There are a few more tweaks needed to improve how it displays, but I’ll leave that to you. Happy coding!!!

Comments
Blog post currently doesn't have any comments.

Want to join the conversation?  Leave a comment using the form below!



 Security code