See Joel Program

February 4, 2008

A JavaScript Stack Trace in ASP.NET AJAX

Filed under: AJAX, ASP.NET AJAX — Tags: , , — Joel Rumerman @ 7:11 pm

Update: Source Code Located Here

Something came up in that work recently that I’ve found to be quite useful in my day to day coding sessions and that’s how to create a stack trace in ASP.NET AJAX.

For starters, JavaScript doesn’t provide an easy way of pulling the stack trace of the call so we’re going to have to roll our own.

I’ve seen a couple of different methods of creating the stack trace and the one I’m going to use comes from Helephant.com. I really like this implementation and I’m glad that I was able to poach somebody else’s code to create the stack trace (thx Helen!) rather than have to create mine from scratch.

From Helen’s post on Helephant.com we can see that there are three main functions to generate the stack trace: getFunctionName, getSignature, and stackTrace. Since we’re deep in the ASP.NET AJAX world I’ve updated the code to rely upon it and look more like code written for it. The code is below.

/// <reference name=”MicrosoftAjax.js />
/// Adopted from: http://www.helephant.com/Article.aspx?ID=675
_StackTrace = function() {
_StackTrace.initializeBase(this);
};
_StackTrace.prototype = {
_getFunctionName: function(theFunction) {
if(theFunction.name) {
return theFunction.name;
}
var definition = theFunction.toString();
var name = definition.substring(definition.indexOf(‘function’) + 8,definition.indexOf(‘(‘));
if(name) {
return name;
}
return“anonymous”;
},
_getSignature: function(theFunction) {
var signature = newSys.StringBuilder(this._getFunctionName(theFunction));
signature.append(“(“);
for(var x=0; x < theFunction.arguments.length; x++) {
var nextArgument = theFunction.arguments[x];
if(nextArgument.length > 30) {
nextArgument = nextArgument.substring(0, 30) + “…”;
}
signature.append(String.format(“‘{0}'”, nextArgument));
// comma separator
if(x < theFunction.arguments.length – 1) {
signature.append(“, “);
}
}
signature.append(“)”);
return signature.toString();
},
createStackTrace: function(startingPoint) {
var stackTraceMessage = newSys.StringBuilder(“Stack trace: \n”);
var nextCaller = startingPoint;
while(nextCaller) {
stackTraceMessage.appendLine(this._getSignature(nextCaller));
nextCaller = nextCaller.caller;
}
stackTraceMessage.appendLine();
stackTraceMessage.appendLine();
return stackTraceMessage;
}
};
_StackTrace.registerClass(“_StackTrace”);
Sys.Application.add_init(
function() {
StackTrace = new_StackTrace();
}
);
Sys.Application.notifyScriptLoaded();

Looking at the code, its basic job is to walk the caller pointer attached to the implicit arguments variable available in every function and derive a stack trace. Pretty straigh-forward.

So you might be thinking, if somebody else wrote the stack trace code, why is this guy writing a blog entry and not providing anything new except for a few minor tweaks to the stack trace code? Well, turns out that the stack trace is only 1/2 the battle. If you use this stack trace code or any other stack trace code that you might have written or come across, you’re going to run into a seriously annoying problem if your JavaScript uses the prototyping feature to construct objects. If you use the prototype feature to create your object and then attempt to pull the stack trace, all of your method names are going to be anonymous, which is really unhelpful. To illustrate this problem, we’ll use another object defined below and then execute the sayHello method from a test page.

/// <reference name=”MicrosoftAjax.js” />
Type.registerNamespace(“Animal”);Animal.Dog = function() {this._speech = “Arf!”;};
Animal.Dog.prototype = {
_speak: function() {
var trace = StackTrace.createStackTrace(arguments.callee);
alert (trace);
},
sayHello: function() {
this._speak();
}
};
Sys.Application.notifyScriptLoaded();

In this object we expose a public method, sayHello off of our Animal.Dog object. Nothing important at here except that in our _speak method we make a call to our StackTrace class and execute the createStackTrace method.

Finally, we create a small test page that executes the sayHello method when it loads. The important section is listed below.

<asp:ScriptManagerID=”SM1″runat=”server”>
<Scripts>
<asp:ScriptReferencePath=”~/StackTrace.js” />
<asp:ScriptReferencePath=”~/StackTraceTester.js” />
</Scripts>
</asp:ScriptManager>
<script type=”text/javascript”>
functiontester () {
var test = newAnimal.Dog();
test.sayHello();
}
Sys.Application.add_init(tester);
</script>

Executing the following code gives us the following output.

Stack Trace

Reading the stack trace from top to bottom states that we executed an anonymous method, followed by another anonymous method, followed by our tester method, and so on. What’s striking about this stack trace is how useless it is! The anonymous method name does not help us at all for figuring out where our stack trace originated from. Can you imagine how much of a pain this would be if our stack was deeper and we had a large library of code?

Anyways, we can fix this problem, and it requires us using a technique seen in the MicrosoftAjax.debug.js file; the main ASP.NET AJAX file. In that file, Microsoft provides what can best be described as debug method names for its methods so that “anonymous” doesn’t appear in the call stack. For this example, we’ll update our Animal.Dog classes well as our StackTrace class using this method. Below is the code from the updated Animal.Dog class and the StackTrace class is updated similarly.

/// <reference name=”MicrosoftAjax.js />
Type.registerNamespace(“Animal”);
Animal.Dog = functionAnimal$Dog() {
this._speech = “Arf!”;
};
Animal.Dog.prototype = {
_speak: functionAnimal$Dog$_speak() {
var trace = StackTrace.createStackTrace(arguments.callee);
alert (trace);
},
sayHello: functionAnimal$Dog$sayHello() {
this._speak();
}
};
Sys.Application.notifyScriptLoaded();

We’ve made changes to both the constructor and the methods. In the constructor we named our constructor function Animal$Dog. We named it using the dollar sign instead of the period (.) because in JavaScript a period is not valid in a function name. For the functions, we named them using the object type followed by the name of the function.

Note: Microsoft does this slightly differently because older versions of Safari don’t understand the named functions. Bertrand blogged about this method and that problem here. I’ve found that Safari 3 Beta on Windows and later versions of Safari 2 on Macs don’t have this problem. If you’re trying to be backwards compatible with older Safari browsers this method would need more testing.

Now when we execute our test page we get the following output.

Stack Trace2

As you can see, our anonymous methods that were present in the first stack trace have turned into named methods. This is quite useful for tracing our execution. Not only does this provide us with a way to build a stack using our StackTrace object, but it gives us the method names in the Call Stack window in Visual Studio.

Call Stack Window

About these ads

13 Comments »

  1. Very neat trick! I didn’t know it was possible to give your prototype functions names like that. :)

    Comment by Helen — February 5, 2008 @ 1:20 am

  2. [...] (lineNumber). We create another variable, stackTrace that uses our previously defined StackTrace object to create the stack trace information for the erroring [...]

    Pingback by JavaScript Error Publishing using ASP.NET AJAX « See Joel Program — February 5, 2008 @ 10:54 pm

  3. Thanks Helen!

    The StackTrace object is proving to help catch my JS errors all over the place!

    Comment by Joel Rumerman — February 5, 2008 @ 10:57 pm

  4. [...] JavaScript Stack Traces in ASP.NET AJAX and JavaScript Error Publishing using ASP.NET AJAX: Joel Rumerman has put together two nice posts that detail some god ways to capture JavaScript stack trace information, as well as to report JavaScript errors using ASP.NET AJAX. [...]

    Pingback by Feb 17th Links: ASP.NET, ASP.NET AJAX, Visual Studio, .NET - ScottGu's Blog — February 17, 2008 @ 11:01 am

  5. [...] JavaScript Stack Traces in ASP.NET AJAX and JavaScript Error Publishing using ASP.NET AJAX: Joel Rumerman has put together two nice posts that detail some god ways to capture JavaScript stack trace information, as well as to report JavaScript errors using ASP.NET AJAX. [...]

    Pingback by BusinessRx Reading List : Feb 17th Links: ASP.NET, ASP.NET AJAX, Visual Studio, .NET — February 17, 2008 @ 11:27 am

  6. [...] JavaScript Stack Traces in ASP.NET AJAX 和 JavaScript Error Publishing using ASP.NET AJAX: Joel Rumerman撰写了2篇好贴,详细讨论了一些如何捕捉JavaScript堆栈跟踪信息,以及如何使用ASP.NET AJAX报告JavaScript错误的好的方法。 [...]

    Pingback by 2月17日链接篇: ASP.NET, ASP.NET AJAX, Visual Studio, .NET - Joycode@Ab110.com — February 17, 2008 @ 2:10 pm

  7. [...] JavaScript Stack Traces in ASP.NET AJAX and JavaScript Error Publishing using ASP.NET AJAX: Joel Rumerman has put together two nice posts that detail some god ways to capture JavaScript stack trace information, as well as to report JavaScript errors using ASP.NET AJAX. [...]

    Pingback by Feb 17th Links: ASP.NET, ASP.NET AJAX, Visual Studio, .NET « .NET Framework tips — February 18, 2008 @ 4:43 am

  8. [...] Tracas de JavaScript en ASP.NET AJAX y publicación de errores de JavaScript con ASP.NET AJAX: Joel Rumerman ha escrito dos post donde nos enseña cómo capturar información de trazas en JavaScript, y cómo reportar errores de JavaScript con ASP.NET AJAX. [...]

    Pingback by Enlaces 17 de Febrero: ASP.NET, ASP.NET AJAX, Visual Studio, .NET « Thinking in .NET — February 18, 2008 @ 9:50 am

  9. [...] JavaScript Stack Traces in ASP.NET AJAX and JavaScript Error Publishing using ASP.NET AJAX: Joel Rumerman has put together two nice posts that detail some god ways to capture JavaScript stack trace information, as well as to report JavaScript errors using ASP.NET AJAX. [...]

    Pingback by Feb 17th Links: ASP.NET, ASP.NET AJAX, Visual Studio, .NET - Mirrored Blogs — February 19, 2008 @ 11:51 pm

  10. [...] A JavaScript Stack Trace in ASP.NET AJAX « See Joel Program (tags: javascript ASP.NET lazycoder) Post a comment — Trackback URI RSS 2.0 feed for these comments This entry (permalink) was posted on Wednesday, February 20, 2008, at 3:22 am by Scott and categorized in Links. [...]

    Pingback by links for 2008-02-20 | Lazycoder — February 20, 2008 @ 2:22 am

  11. [...] A JavaScript Stack Trace in ASP.NET AJAX (Joel Rumerman) [...]

    Pingback by » Daily Bits - February 20, 2008 Alvin Ashcraft’s Daily Geek Bits: Daily links, development, gadgets and raising rugrats. — February 20, 2008 @ 9:10 am

  12. [...] JavaScript Stack Traces in ASP.NET AJAX and JavaScript Error Publishing using ASP.NET AJAX: Joel Rumerman has put together two nice posts that detail some god ways to capture JavaScript stack trace information, as well as to report JavaScript errors using ASP.NET AJAX. [...]

    Pingback by Feb 17th Links: ASP.NET, ASP.NET AJAX, Visual Studio, .NET - Programming — March 6, 2008 @ 2:03 pm

  13. [...] ASP.NET users, Joel Rumerman has created an ASP.NET Ajax version of the trace code and has included a neat trick for getting useful function names from [...]

    Pingback by Helephant.com » Blog Archive » DIY javascript stack trace — November 13, 2008 @ 2:08 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: