Troubleshooting Partial Rendering Errors in ATLAS and ASP.NET 2.0
This article helps you resolve some common errors in ASP.NET 2.0 and ATLAS.
Introduction
In my previous article, I explained how to partially render pages in ASP.NET 2.0 and ATLAS with client script. In this article, I will try to help you troubleshoot a series of common errors when you implement the ICallbackEventHandler
and IPostBackEventHandler
interfaces. To be precise, for each error, I added a sample code to generate the problem and also necessary code that helps you to eliminate the problem.
Using the Code
Error: ‘theForm._EVENTTARGET’ is null or not an object (Applies to: ASP.NET - ATLAS)
This error may appear because of the way you dynamically manipulate your HTML document. If you use non-W3C standard Document Object Model (DOM) methods to dynamically manipulate your document, expect this problem to happen. A good example of this is when you use the non-standard “innerHTML
” property of your objects. This may pose a huge compatibility issue with your existing JavaScript code. Hopefully, ASP.NET adds support for non-standard methods and properties, but until then, you need to revise your JavaScript code. I could not find any documentation that shows this behavior by design, therefore, possibly it is a bug.
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
//@ I encourage you to use this sample code!
//@ This sample is provided under the terms of the GNU General Public License.
//@ for more information visit my blog at TheMorningOutline.com. Cheers!
//@ Shahin
// Implement ICallbackEventHandler
public partial class CallbackSample : System.Web.UI.Page, ICallbackEventHandler
{
//Callback Counter
static int i;
string strMessagetoClient;
protected void Page_Load(object sender, EventArgs e)
{
strMessagetoClient = "";
if (IsCallback)
{
i++;
// if you make any client side changes here,
// they are lost and never will be shown
Label1.Text = "I am lost";
// Keep track of my Callback time
strMessagetoClient = String.Format("For the {1} " +
"time Callback raised at {0}.",
DateTime.Now.TimeOfDay.ToString(),
i.ToString());
}
// Make sure a Postback doesn't get here
else if (!IsPostBack)
{
// Initilize the Application
i = 0;
// Javascript Plumbing. You only need to
// this when the page loads for the first time
//if you have NO other Postbacks
ClientScriptPlumbing();
}
// Make changes to the calendar. After a postback
// you can see the calendar changes.
// click on the dummy postback button
// to cause a full postback
Calendar1.SelectedDate = DateTime.Today.AddDays(i);
Label1.Text = String.Format("Total number" +
" of Callbacks:{0}", i.ToString());
ClientScriptPlumbing();
}
private void ClientScriptPlumbing()
{
// Get a reference of Javasctipt Callback function
string functionRef = Page.ClientScript.GetCallbackEventReference(this,
"args", "getServerData",
"'this is context from server'");
// Make a custm function to call it
string strCallback = "function CallServer(args," +
"context){" + functionRef + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"CallServer", strCallback, true);
//Register other client functions
Page.ClientScript.RegisterClientScriptBlock(
this.GetType(), "CommonScripts", @"
function btnBug_onclick() {
CallServer('Hi','Client Call');
// non-standard
document.body.innerHTML+='<P style=\'color:red;\' > ' +
'From this point, the postback from' +
' controls doesnt work. Try the Calendar!(to'+
'resolve this issue comment this line ' +
'of JS and use the DOM version )<P>';
//standard
//uncomment the lines below and comment the above line
/*
newDiv = document.createElement('div');
newDiv.id='newDiv';
var mytext=document.createTextNode('I was added' +
' dynamically but unlike innerHTML' +
' I dont harm your Calendar Postbacks. Use DOM!');
newDiv.appendChild(mytext);
document.body.appendChild(newDiv);*/
}
//Clicking on Button1 makes a Callback
//and triggers RaiseCallbackEvent
function Button1_onclick()
{
CallServer('Hi','Client Call');
return false;
}
// Receive the string returned by GetCallbackResult
function getServerData(args, context)
{
myCustomFunc(args);
}
// My JS scripts that takes care of partial rendering
function myCustomFunc(strArgs)
{
var NewTxtArea= document.getElementById('NewTxtArea');
if (!NewTxtArea )
{
var NewTxtArea = document.createElement('textarea');
NewTxtArea.id = 'NewTxtArea';
NewTxtArea.rows = 10;
NewTxtArea.cols = 100;
document.body.appendChild(NewTxtArea);
}
NewTxtArea.value+=strArgs + '\n';
}
"
, true);
}
//This is called by CallServer Javascript
public void RaiseCallbackEvent(string eventArgument)
{
// Notice that the any changes you make to webcontrols won't get rendered
Label1.Text = "This text is never shown!!!";
strMessagetoClient += "The server side is updated," +
" but I am just a javascript " +
"and too lazy to update your calendar.";
strMessagetoClient += "To update do a Postback " +
"by clicking on the calendar .";
}
//Retrun strMessagetoClient to the clinet.
//Notice that it does not refresh your page
//but it calls the registered javascript getServerData function
public string GetCallbackResult()
{
return strMessagetoClient;
}
}
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="_EVENTTARGETisNullError .aspx.cs"
Inherits="CallbackSample" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>www.themorningoutline.com</title>
</head>
<body id='myBody'>
<form id="form1" runat="server">
<asp:Label ID="Label1" runat="server"
Height="8px" Text="Callback"
Width="255px">
</asp:Label>
<asp:Calendar ID="Calendar1"
runat="server"></asp:Calendar>
<input id="Button1" language="javascript"
onclick="return Button1_onclick()"
type="button" value="Callback" />
<input id="btnBug" type="button" value="Bug me!"
language="javascript"
onclick="return btnBug_onclick()" /><br />
</form>
</body>
</html>
Error: ‘_pendingCallbacks[...].async’ is null or not an object (Applies to: ASP.NET – ATLAS)
This error appears when a JavaScript function, which is called by GetCallbackResult
, utilizes a variable called ‘i
’. This bug was fist discussed back in 2005 in the comment section of a post from Rick Strahl's Web Log called "Script Callbacks in ASP.NET 2.0 interface changes in Visual Studio July CTP" and it exists until today. Apparently, “i
” is declared as a global variable in ASP implementation, and by changing it, you are messing with ASP.NET auto-generated scripts. To resolve this problem, declare your variable as a local variable in the function.
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
//@ I encourage you to use this sample code!
//@ This sample is provided under the terms of the GNU General Public License.
//@ for more information visit my blog at TheMorningOutline.com. Cheers!
//@ Shahin
// Implement ICallbackEventHandler and IPostBackEventHandler
public partial class PostbackSample : System.Web.UI.Page,
ICallbackEventHandler, IPostBackEventHandler
{
//Callback Counter
static int i;
//Postback Counter
static int j;
string strMessagetoClient;
static string CallbackTime;
protected void Page_Load(object sender, EventArgs e)
{
strMessagetoClient = "";
if (IsCallback)
{
i++;
// Keep track of my Callback time
CallbackTime = DateTime.Now.TimeOfDay.ToString();
strMessagetoClient = String.Format("For the {1} time" +
" Callback raised at {0}.",
CallbackTime, i.ToString());
// if you make any clinet side changes here,
// they are lost and never be shown
Label1.Text = "I am lost";
}
else if (IsPostBack)
{
j++;
// Javascript Plumbing. Normally You would
// do this in your initial load and
// RaisePostBackEvent but because Atlas oesn't
// raise that event you need
// to put it here for Atlas partial Postbacks
ClientScriptPlumbing();
}
else
{
// Initilize the Application
i = 0;
CallbackTime = "Not Yet";
ClientScriptPlumbing();
}
// When a Postback occurs it will take care of Callback UI changes
// if you want to make UI changes during a Callback and later show them
// by a postback you must put them in Page_load event here
Calendar1.SelectedDate = DateTime.Today.AddDays(i);
Label1.Text = String.Format("Total Callbacks count:{0}" +
" Last Callback Occurred at {1}",
i.ToString(), CallbackTime);
}
private void ClientScriptPlumbing()
{
// Get a reference of Javasctipt Callback function
string functionRef = Page.ClientScript.GetCallbackEventReference(this,
"args", "getServerData",
"'this is context from server'");
// Make a custom function to call it
string strCallback = "function CallServer(args,context){" +
functionRef + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"CallServer", strCallback, true);
// Get a reference of Javasctipt Postback function
functionRef = Page.ClientScript.GetPostBackClientHyperlink(this,
"PostBack");
// Make a custm function to call it
string strPostBack = "function PostServer(args,context){" +
functionRef + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"PostServer", strPostBack, true);
//Register other client functions
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"CommonScripts", @"
var INeedABug=false;
function btnBugATLAS_onclick() {
INeedABug=true;
newDiv = document.createElement('div');
newDiv.id='newDiv';
var mytext=document.createTextNode('To resovle this issue' +
' uncomment the var i line' +
' in getServerData function' );
newDiv.appendChild(mytext);
document.body.appendChild(newDiv);
CallServer('bug!','Client Callback');
}
function Button1_onclick()
{
CallServer('Hi','Client Callback');
return false;
}
function Button2_onclick()
{
PostServer('Hi','ClientPostback');
return false;
}
function getServerData(args, context)
{
//uncomment this to resolve the issue
// var i
myCustomFunc(args);
if (INeedABug) i++;
}
function myCustomFunc(strArgs)
{
var NewTxtArea= document.getElementById('NewTxtArea');
if (!NewTxtArea )
{
var NewTxtArea = document.createElement('textarea');
NewTxtArea.id = 'NewTxtArea';
NewTxtArea.rows = 10;
NewTxtArea.cols = 100;
document.body.appendChild(NewTxtArea);
}
NewTxtArea.value+=strArgs + '\n';
}
"
, true);
}
//This is called by CallServer Javascript
public void RaiseCallbackEvent(string eventArgument)
{
// Notice that any changes you make here, won't
// get rendered
Label1.Text = "This text is never shown!!!";
strMessagetoClient += "The server side is updated, " +
"but I am just a javascript " +
"and too lazy to update your " +
"calenadr, ask Postback to do it.";
}
//Retrun strMessagetoClient to getServerData.
//Notice that this does not refresh your page but it calls
//the registered javascript getServerData function
public string GetCallbackResult()
{
return strMessagetoClient;
}
//This is called by PostServer Javascript and
//can be used to force UpdatePanel to refresh
public void RaisePostBackEvent(string str)
{
// Your client side changes here will get rendered
Calendar2.SelectedDate = DateTime.Today.AddDays(j);
Label2.Text = String.Format("Total Postback count:{0}" +
" Last Postback Occurred at {1}", j.ToString(),
DateTime.Now.TimeOfDay.ToString());
}
}
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="_pendingCallbacksError.aspx.cs"
Inherits="PostbackSample" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>www.themorningoutline.com</title>
</head>
<body id='myBody'>
<form id="form1" runat="server">
<atlas:ScriptManager ID="ScriptManager1"
runat="server" EnablePartialRendering="True">
</atlas:ScriptManager>
<div>
</div>
<atlas:UpdatePanel ID="up1" runat="server">
<ContentTemplate>
<asp:Label ID="Label1" runat="server"
Text="Callback" Height="8px" Width="505px"></asp:Label>
<asp:Calendar ID="Calendar1" runat="server"></asp:Calendar>
<asp:Label ID="Label2" runat="server"
Text="PostBack" Width="504px"></asp:Label>
<asp:Calendar ID="Calendar2" runat="server"></asp:Calendar>
<input id="Button1" language="javascript"
onclick="return Button1_onclick()"
type="button" value="Callback" />
<input id="Button2" language="javascript"
onclick="return Button2_onclick()"
type="button" value="Postback" />
<input id="Button3" language="javascript"
onclick="return btnBugATLAS_onclick()"
type="button" value="Bug me!" /><br />
</ContentTemplate>
</atlas:UpdatePanel>
</form>
</body>
</html>
Error: JavaScript alert “unknown error” (Applies to: ATLAS)
This error may appear when you are dealing with string
s that contain tags in your JavaScript and you place your JavaScript in the head
section or a separate file. Also, if you have any other tags that are not properly closed, you may get this error. To resolve this problem, always put your JavaScript code inside <!-- -->
, or better use the ClientScript
object of ASP.NET to register your JavaScript functions. You are very prone to get this error if you are dealing with XML in your JavaScript code.
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>www.themorningoutline.com</title>
<script type='text/javascript'>
//@ TheMorningOutline.com provided this under the terms of the GNU GPL.
//Put the following function within <!-- --> or move it
to the body to get rid of unknown error
function genXML()
{
var strArgs= '<?xml version=\'1.0\' standalone=\'yes\'?>'
strArgs += '<Callback>'
strArgs += '</Callback>'
return strArgs;
}
</script>
</head>
<body id='myBody'>
<form id="form1" runat="server">
<atlas:ScriptManager ID="ScriptManager1"
runat="server" EnablePartialRendering="True">
</atlas:ScriptManager>
<div>
</div>
<atlas:UpdatePanel ID="up1" runat="server">
<ContentTemplate>
<asp:Calendar ID="Calendar1" runat="server">
</asp:Calendar>
Click the calndar for an unknown error!
</ContentTemplate>
</atlas:UpdatePanel>
</form>
</body>
</html>
Error: Your Callbacks/Postbacks stop working after the first successful Postback (Applies to ATLAS)
This problem may happen when your client scripts are not properly registered back on the client after ATLAS makes a partial postback. To resolve this problem, use the ClientScript
object in the Page_Load
event to register your client scripts.
protected void Page_Load(object sender, EventArgs e)
{
if (IsCallback)
{
// You don't need to re-register your
// scripts on each Callback
// For Callbacks,you only do it when
// you page loads the first time.
}
else if (IsPostBack)
{
// Normally You would do your JavaScript
// Plumbingthis in your initial load and
// RaisePostBackEvent but because Atlas
// doesn't raise that event you need
// to put it here for Atlas partial Postbacks
ClientScriptPlumbing();
}
else
{
// Initilize the Page
ClientScriptPlumbing();
}
}
private void ClientScriptPlumbing()
{
//Register other client functions
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"CommonScripts", @"
function foo() {}
....
"
, true);
}
Conclusion
This article explained how to resolve some of the common issues with ASP.NET ATLAS and client calls. Later in another article, I will discuss the new ATLAS text/xml-script and the ControlExtender
toolkit. I will give you some ideas about how to use JavaScript to achieve the same functionality in an easy and comprehensive fashion. You can leave your comments here.
Cheers!