Posted on March 4, 2008 07:13 by mcollins

Let's face it, one of the problems that has always plagued client-side development in the browser is that JavaScript can be a pain to debug.  As a developer, you have no knowledge if the browser is actually executing your code or what is happening when a page loads.  You refresh the page in the browser, wait, and see if your latest changes worked.  If not, you then have to mentally figure out what happened inside your script without really having any tools to see inside.  Sure, Microsoft makes a script debugger for IE, and sometimes script debugging does work inside of Visual Studio, but I've found a lot of times where the scripts won't load in the debugger or breakpoints that I set inside of Visual Studio aren't tripped.  When that doesn't work, I've typically had to fall back to putting alerts into my code and going through many popup message boxes to tell me what's going on.

Fortunately, ASP.NET AJAX has support to make debugging easier through the Sys.Debug JavaScript object.  The Sys.Debug object provides a trace method for outputting simple messages to a trace console and a traceDump method for outputting object contents to the trace console.  So what is the trace console?  If your browser has a JavaScript console then your messages will go there.  Internet Explorer may have one, but I've never found it.  So the other approach is to make your own inside of your web page, which turns out to be quite easy to do.  You simply create a TEXTAREA element inside of your web page and set its ID attribute to the value TraceConsole.  The Sys.Debug object will automatically find it and append your trace output to that element.

   1: <%@ Page Language="C#" AutoEventWireup="true" ... %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   4:     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5: <html xmlns="http://www.w3.org/1999/xhtml">
   6: <head runat="server">
   7:     <title>Untitled Page</title>
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <asp:ScriptManager ID="ScriptManager1" runat="server">
  12:     </asp:ScriptManager>
  13:     <div>
  14:     </div>
  15:     <textarea id="TraceConsole" rows="30" cols="60"></textarea>
  16:     </form>
  17:  
  18:     <script type="text/javascript">
   1:  
   2:     <!--
   3:         Sys.Application.add_init(function() {
   4:             Sys.Debug.trace('Initializing page.');
   5:             
   6:             // Create client components. Initialize the page.
   7:             
   8:             Sys.Debug.trace('Page initialized.');
   9:         });
  10:         
  11:         function pageLoad() {
  12:             Sys.Debug.trace('pageLoad called.');
  13:             
  14:             // Begin executing the business logic for the page. Attach
  15:             // event handlers to elements, etc.
  16:             
  17:             Sys.Debug.trace('pageLoad completed.');
  18:         }
  19:         
  20:         function pageUnload() {
  21:             Sys.Debug.trace('pageUnload called.');
  22:             
  23:             // The page is being unloaded. If you attached event
  24:             // handlers in pageLoad, detach them here to prevent
  25:             // memory leaks.
  26:             
  27:             Sys.Debug.trace('pageUnload completed.');
  28:         }
  29:     //-->
  30:     
</script>
  19:  
  20: </body>
  21: </html>

Here's a screen shot of the trace output in the page:

image

Of course, what happens if you don't want this console to show up on pages in the production environment.  You can wrap the trace console element inside of a Panel control, and then choose to show or hide the panel depending on whether the page is in debug mode or not.

   1: <%@ Page Language="C#" AutoEventWireup="true" ... %>
   2:  
   3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   4:     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5: <html xmlns="http://www.w3.org/1999/xhtml">
   6: <head runat="server">
   7:     <title>Untitled Page</title>
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <asp:ScriptManager ID="ScriptManager1" runat="server">
  12:     </asp:ScriptManager>
  13:     <div>
  14:     </div>
  15:     <asp:Panel ID="DebugPanel" runat="server" Visible="false">
  16:         <textarea id="TraceConsole" rows="30" cols="60"></textarea>
  17:     </asp:Panel>
  18:     </form>
  19:  
  20:     <script type="text/javascript">
   1:  
   2:     <!--
   3:         Sys.Application.add_init(function() {
   4:             Sys.Debug.trace('Initializing page.');
   5:             
   6:             // Create client components. Initialize the page.
   7:             
   8:             Sys.Debug.trace('Page initialized.');
   9:         });
  10:         
  11:         function pageLoad() {
  12:             Sys.Debug.trace('pageLoad called.');
  13:             
  14:             // Begin executing the business logic for the page. Attach
  15:             // event handlers to elements, etc.
  16:             
  17:             Sys.Debug.trace('pageLoad completed.');
  18:         }
  19:         
  20:         function pageUnload() {
  21:             Sys.Debug.trace('pageUnload called.');
  22:             
  23:             // The page is being unloaded. If you attached event
  24:             // handlers in pageLoad, detach them here to prevent
  25:             // memory leaks.
  26:             
  27:             Sys.Debug.trace('pageUnload completed.');
  28:         }
  29:     //-->
  30:     
</script>
  21:  
  22: </body>
  23: </html>

You can see here on line 15 that I wrapped the TEXTAREA element with an ASP.NET Panel control named DebugPanel.  Initially the panel's Visible property is set to false, meaning that the Panel control and it's contents won't be rendered by the page when the page is requested.  In the code-beside file for the page, I handle displaying the Panel control when the Page.Load event is raised:

   1: public partial class _Default : System.Web.UI.Page {
   2:     protected void Page_Load(object sender, EventArgs e) {
   3:         ShowDebugConsole();
   4:     }
   5:  
   6:     [Conditional("DEBUG")]
   7:     private void ShowDebugConsole() {
   8:         DebugPanel.Visible = true;
   9:     }
  10: }

In the code-beside file for the page, by Page_Load handler is being called when the page is being requested by a user.  Inside of the event handler, it's invoking the ShowDebugConsole method.  The ShowDebugConsole method is simply setting the value of the Visible property on the DebugPanel control to true to indicate that the debugging console should be rendered in the page's output.  The real magic here is in the use of the Conditional attribute on the ShowDebugConsole method.  When the page is being compiled in debug mode, then the C# compiler will define the DEBUG symbol.  When the DEBUG symbol is defined, the compiler will compile the code inside of the ShowDebugConsole method, and thus the debugging console will be displayed in the rendered HTML and on the browser.  When the page is being compiled in release mode, the DEBUG symbol is not defined and the code inside of the ShowDebugConsole method is not compiled.  The ShowDebugConsole method will still be included in the generated IL code, but the method will be empty and will simply return to the caller.

The next part of the magic is how do you tell an ASP.NET application that it's running in debug mode versus release mode.  There are two ways of doing this.  If you're using an ASP.NET Web Application project for your web application, or if you are using a Web Deployment Project to compile and package your web application, then the build mode is determined by the compiler at build time.  For example, this is handled from the toolbar in Visual Studio by choosing between a debug build or a release build.  The other ASP.NET mode for web applications is to deploy the .aspx files side-by-side with the .cs files and ASP.NET will compile pages as they are requested.  In this case, you need some other way to tell ASP.NET to compile the pages in debug or release mode.  It turns out that this can be done using the web.config file:

   1: <?xml version="1.0"?>
   2: <configuration>
   3:     <system.web>
   4:         <compilation debug="true">
   5:             <assemblies>
   6:                 ...
   7:             </assemblies>
   8:         </compilation>

Above is a fragment of my web.config file.  Line 4 is the line that we need to focus on.  Notice that the debug attribute on the compilation element is set to true.  When this value is set, then the runtime ASP.NET compiler will build the pages in debug mode and will define the DEBUG symbol for the C# compiler.  Setting the value of the debug attribute to false will turn off debug mode for the web application.  You can therefore control whether the debugging console appears on your pages using the web.config file.

In summary, the Sys.Debug object provides a lot of advantages to JavaScript debugging at runtime over using the JavaScript alert function.  First, you don't need to deal with those annoying message boxes and removing them after you've fixed your bug.  Second, by using a little .NET and ASP.NET creativity, you can add debugging support to your pages that you can easily disable in the production environment by modifying your web.config file and not your source code.  The end result is that you have a page that is easier to debug and easier to maintain in the long run.

Technorati tags: , , ,


Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Related posts

Comments

April 24. 2008 01:26

Its GoodI like this
|

SUresh

April 24. 2008 01:27

Its GoodI like this
|

SUresh

Add comment


 

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

November 20. 2008 05:54

|