Kevin Grohoske

Senior Software Engineer 
MCPD-WEB, MCPD-WIN, MCSD

Creating and Displaying Dynamic Serverside Error Messages with MS Ajax

Tuesday, August 26, 2008 05:25 | posted by: kevin

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!!!

Tags:

PermaLink   E-Mail Article   RSS Comment Feed  

Infragistics and Peter Blum Validation “Page is still loading” Ajax Error

Friday, February 01, 2008 05:01 | posted by: kevin

I recently encountered a compatibility issue with Peter Blum validation controls and Infragistics WARP (Web Async Refresh Panels). Luckily it has already been resolved in the latest version (3.0.11.5000) of Peter Blum’s controls, but it is not documented well on the Peter Blum site or support forums.

If you do not register the WARP panels with the following Peter Blum command you will get “Page is still loading. Please wait” when you try to change data after the page has been updated via a WARP postback.

Steps to reproduce:

If you have a simple page with two WARP panels one that displays the data fields data and the other with a button to update/save.

 

  1. <!--[if !supportLists]--> <!--[endif]-->Load page
  2. <!--[if !supportLists]--> <!--[endif]-->Modify data and press Save via a button in a WARP panel
  3. <!--[if !supportLists]--> <!--[endif]-->WARP panel with data gets updated
  4. <!--[if !supportLists]--> <!--[endif]-->Attempt to change the data.
  5. <!--[if !supportLists]--> <!--[endif]-->Page will show a modal javascript dialog stating, “Page is still loading. Please wait”.
protected void Page_Load(object sender, EventArgs e) { PeterBlum.VAM.AJAXManager.Current.AllInAJAXUpdate = true; PeterBlum.VAM.AJAXManager. UsingInfragisticsAJAX(###WARPPanelName###); //one line for each warp panel PeterBlum.VAM.AJAXManager. UsingInfragisticsAJAX(###SecondWARPPanelName###); //one line for each warp panel }

Tags:

PermaLink   E-Mail Article   RSS Comment Feed  

Yesterday I was trying to help a co-worker that had an odd problem in their ASP.NET 2.0 application. Despite the fact that the class was in the ‘App_Code’ directory and the class was within the same namespace yet it could not accessed/recognized. We were receiving the error, “The type or namespace name ‘example’ could not be found (are you missing a directive or an assembly reference?)”.

Working through the issue I found some interesting possible issues.

1. I could not delete and create a new ‘App_Code’ directory. When I right clicked the project, chose Add, and chose Add Folder, there was no listing for the App_Code folder.

2. I though that perhaps the ‘App_Code’ directory was created incorrectly, due to issue #1. So I found and interesting article explaining how any folder could be configured with the same behavior as the ‘App_Code’ directory with a the simple xml change in the web.config listed below. Unfortunately this did not fix the problem, but could come in handy in the future.

<configuration>
<system>
<compilation>
<codesubdirectories>
<add directoryname="Subdirectory"></add>
</codesubdirectories>
</compilation>
</system>
</configuration>

3. Finally, I found the problem was that the build option on the class file was set to ‘Content’ rather than ‘Compile’. This made me curious of the different settings available and how they can be used. Here are my initial impressions of each.

  • Content - includes the file in the build/deployment, but does not compile.
  • Embedded Resource - used for situations where you want to utilize the source of the file (for example javascript source for AJAX). There are mechanisms to access the resource through the URL back on the server. Here is a good article on the subject.
  • Compile - compiles the class when you build/deploy and includes MSIL as part of the source code.
  • None - not sure when you’d use this option

Tags:

PermaLink   E-Mail Article   RSS Comment Feed