Main Menu
Knowledge Base
Product Registration
Log an Incident
Request a Feature
Search Incidents/Bug Reports


Search KB

Please note: In an effort to better serve you, we are in the process of restructuring DevCenter. In the process, we have moved many items that you may be used to finding in DevCenter over to the Main Site. If you are having trouble locating something, please try looking at the following places:

Debug JavaScript in ASP.NET Apps
View Printer Friendly Version

Brian Clark
ASP.NETpro
Page Options
Average Rating:
2 out of 10

Rate this page
Print this page
E-mail this page
Add to Favorites

Posted:

Tuesday, December 09, 2003

Applies To:


  • ASP.NET
  • .NET Framework
  • JavaScript

Summary:

Your pages need JavaScript, both for logic and UI. But debugging JavaScript code can be a pain, unless you know a few tricks.

ASP.NET has many advantages over classic ASP in the area of debugging. You can now easily debug your server-side code using the full power of a modern debugger such as Visual Studio .NET. This, along with the introduction of server controls and a postback architecture, has simplified Web-based development. But what about the other half of a Web application, the client-side script?

Although server controls and postbacks have reduced the need for Web developers to interact with JavaScript in an ASP.NET application, many developers are learning that they cannot forget about client-side scripting altogether.
 
Developers creating Web pages designed to display even a moderate amount of data know the cost of posting back to the server. Using JavaScript to perform simple tasks minimizes the number of roundtrips to the server, potentially avoiding unnecessary queries to the database and reducing the number of times the ViewState is pushed over the wire.

Besides reducing the amount of network traffic, the use of client-side JavaScript enables ASP.NET developers to provide a richer and more interactive experience to the end-user. By moving appropriate functionality from the server to the client you provide the user with instant responsiveness and feedback without the latency implicit in a postback. Balancing functionality between both the client and the server helps reduce some of the load on the Web server, which in turn yields better server response times.

A substantial roadblock to using JavaScript, though, is that it can be difficult to write and debug.

First, IntelliSense for JavaScript is limited at best, which leads to errors in the initial coding stage. Because JavaScript is case-sensitive, the lack of IntelliSense can be aggravating - particularly for developers turning to ASP.NET from a case-insensitive language like Visual Basic.

Also, when a browser's JavaScript error message provides a line number to look at, it often doesn't match the line numbers indicated in the code. The line number will get you in the right area, but after that, it often becomes a guessing game.

Furthermore, if you try putting a breakpoint in the JavaScript in your ASPX, you'll find that when running the project, control will not stop on it and, at best, you may get the not-so-helpful message, "Breakpoint will not be hit, symbols have not been loaded for this document."

Tap into HTML


With Internet Explorer 6 and VS .NET, Microsoft has provided a way to tap into the HTML and JavaScript that Internet Explorer is running, thereby closing the loop in the debugging cycle. By closing this hole developers can now debug their entire application in a single IDE - from client-side script to server-side code, and possibly right through to the database.

Unfortunately for most developers, this won't work without some basic set up. To verify that Internet Explorer is set up correctly, open Internet Explorer, choose Tools | Internet Options. Click the Advanced tab and find Disable script debugging about halfway down the list. Make sure there is no check in the box next to this option. Click OK and close Internet Explorer. The browser is now ready to work with Visual Studio .NET to debug your application.

To begin exploring the basic functions of the debugger, start a new WebForms project and run it without adding any controls or code. When the empty project loads in Internet Explorer, return to Visual Studio and open the Running Documents window by selecting Debug | Windows | Running Documents from the Debug menu.

The Running Documents window will appear docked on the right edge of the IDE. The name of the page, "WebForm1.aspx", will appear in the window. Double-click the page and the HTML rendered to the browser when the ASPX page was evaluated by the server will be shown in a code window on the left. The HTML rendered by the ASPX page can be seen by double-clicking the page in the Running Documents window.

The code provided by the Running Documents window is where a developer can set breakpoints and step through the code, just like in server-side code. Stop the project and bring up the form designer.

As an example, a developer might need to create a custom validator that ensures the user has selected a valid item from a dropdown list. Often times a developer does not want users to be able to choose the first item in the list, as this might be a prompt such as "Select an item." (If you are not familiar with custom validators, check out the .NET Framework General Reference for the CustomValidator control at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconcustomvalidatorcontrol.asp.)

In this example, create two dropdown lists, one prompting users to "Choose your favorite animal..." (and list various animals). The other should ask the user to "Choose your favorite color..." (and list a few colors).

After configuring a new custom validator on the page to validate the first dropdown, set its ClientValidationFunction to clientvalidate and insert the following validation code into the page's header section (this code will be called by the ASP.NET custom validator control):

<script>
function clientvalidate(source, args){
   var dropdown =
  document.getElementById(source.controltovalidate);
  if (dropdown.selectedindex == 0){
   args.IsValid = false;
  }   else {
  args.IsValid = true;
  }
 }
</script>

 

The ClientValidationFunction will be called by the CustomValidator each time the value of the dropdown changes.

In the HtmlView, add an OnServerValidation event like this:

<asp:CustomValidator OnServerValidate="ServerValidation"/>

Then add the following code, which adds an event handler for ServerValidation. The server-side code is added to the code behind. This code will be called by the ASP.NET custom validator control on browsers that do not support client-side script:

Sub ServerValidation(ByVal source As Object,
  ByVal args As ServerValidateEventArgs)
Dim dl As DropDownList = _
  FindControl(CType(source, CustomValidator) _
  .ControlToValidate)
 
 If dl.SelectedIndex = 0 Then
  args.IsValid = False
 Else
  args.IsValid = True
 End If
End Sub

Another validator will need to be added and configured in the same way for the second dropdown list. Both validators can point to the same client-side script and server-side event.

After adding a new button labeled Submit.

Start the project and choose an animal from the animal dropdown. Correctly, the validation error message doesn't appear. Select the first item in the list again and notice that the error message is still not displayed. This is not the expected functionality. The validation function is called each time the value of the dropdown changes. Because the first item in the list is chosen, the error message should be visible.

To find out what is happening in our custom JavaScript code, double-click the Web page in the Running Documents window and put a breakpoint on the first line of code, where we assign the dropdown list. Switch back to Internet Explorer and select another animal name. Execution of the page will break on the line of code selected. From here, a developer can walk through the code as if it were server code. Press F10 to step through the code and into the else statement. This is correct behavior. Press F5 to continue running the code.

Now select the first item in the same dropdown list so that execution stops at the breakpoint again. This time, however, examine the value of dropdown.selectedindex. Highlight the words "dropdown.selectedindex" and hit Ctrl-Alt-Q or drag the text to a watch window. The watch window shows that dropdown.seletectedindex is undefined. The one major ramification of this is that the comparison will never return true, and args.IsValid will never be set to false. That is, regardless of the dropdown's value, validation will never fail.

Change the text in the Quick Watch window to "dropdown" and hit Enter. The watch window now lists all the members of the "dropdown" object. Scrolling to the bottom, you can see the problem: "selectedindex" is not a property of the dropdown. It should really be "selectedIndex", with a capital "I".

Now that the problem is known the code must be updated. Don't try to update the code here, though, because this view of the code is not editable. Remember, this is what the browser sees; switch back to the ASPX HtmlView to change the code.

Make the change and run the project again; this time it works as expected.

Debug Startup Code


Unfortunately, the technique described above breaks down when you try to debug code that executes on start up, such as from a server-side Page.RegisterStartUpScriptBlock method in the page load event. Because the JavaScript code runs as the page loads, you have no opportunity to return to the IDE to set a breakpoint.

Debugging startup script code requires a different method for debugging. There are three ways to debug startup script. First, start your project with F10. Pressing F10 will load your default startup page in the browser and immediately put you in break mode on the first line of JavaScript. You can then set another breakpoint elsewhere in your code, or you can step through line by line until you reach the line of interest.

Next, run the page, let the error occur, then set the breakpoint and hit F5. This method comes in handy when you receive an unexpected error. After the page has loaded in your browser and you get an error or incorrect behavior, open the appropriate Running Documents window and place a breakpoint where you would have wanted execution to stop. Return to the browser and hit F5. Visual Studio .NET will recognize that this is the same page you loaded before and will keep your breakpoint in place. When execution reaches the breakpoint, control will return to the IDE.

Finally, use the debugger keyword. The debugger keyword works just like a breakpoint. When the JavaScript interpreter reaches this keyword, it halts execution and returns control to the IDE.

To demonstrate the power of the debugger keyword, insert the code shown in Figure 3 behind the click event of our Submit button.

Private Sub Button1_Click(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles Button1.Click
    If Page.IsValid Then                            
      Dim sb As New System.Text.StringBuilder()
      sb.Append("<script>" & vbCrLf)
      sb.Append("dropdown1 = document" _
        & ".getElementById('DropDownList1');" & vbCrLf)
      sb.Append("color = dropdown1." _
  & "value.toLowerCase();" & vbCrLf)
      sb.Append("dropdown2 = document." _
  & "getElementById('DropDownList2');" & vbCrLf)
      sb.Append("animal = dropdown2." _
  & "value.toLowerCase;" & vbCrLf)
      sb.Append("alert('Would you like a" _
  & " ' + color + ' ' + animal + '?');" & vbCrLf)
      sb.Append("</script>")
      Page.RegisterStartupScript("MyStartupScript", _
  sb.ToString())
   End If
End Sub


Figure 3. The code behind the Submit button uses the Page.RegisterStartupScript method to add code that will execute after the page loads in the browser.

Run the project, select values from the dropdown, and click the Submit button. No error message is displayed, but the value in our alert box is not quite what would be expected. Add a "debugger" line and step through the code line-by-line. Add this line after the initial <script> tag illustrated above:

sb.Append("debugger;" & vbCrLf)

Run the project, select values from our dropdowns, and click the Submit button again. This time the page reloads and stops on the word "debugger" Hit F10 to move to the next line and continue stepping through the startup code.

Examining each line of code and the resulting values, notice that the offending line is:

animal = dropdown2.value.toLowerCase;


When a developer is unable to diagnose the problem from a quick glance, the watch window can help out. Bring up Quick Watch again with Ctrl-Alt-Q and enter "dropdown2.value", then add ".toLowerCase". By verifying that the value exists, but that toLowerCase does not, the scope of the problem has been narrowed. The solution is now evident: "toLowerCase" is a method, not a field, and as such, requires parentheses.

Return to the button's click event and fix the code by adding parentheses after ".toLowerCase". Execute the page again. When you are satisfied that the bug has been worked out, remove or comment out the line containing "debugger;".

Note that if the browser executes the debugger statement while not connected to a debugger, it will throw an error and ask you if you would like to debug. As a result, be sure you remove the keyword when you have finished debugging so your end users never see it.

Debugging startup script is a little more difficult than debugging script behind a button click or a validation routine because it is hard to insert a breakpoint at the right place. Starting the page with F10 or using the debugger keyword can help break into the code. From that point, a developer can find the errors in his logic using the same powerful tools he is accustomed to using with server-side code.

Visual Studio .NET provides the same powerful and flexible tools for debugging your client-side code as it does for server-side code. Get the most out of Visual Studio .NET by using the techniques described here to close the loop and debug your entire ASP.NET application in one IDE.

Brian Clark, a developer on leave from Infragistics, is currently pursuing a Master's degree in Computer Science and Systems Engineering at Cornell University. He welcomes your comments and questions at BrianC@infragistics.com.

Article provided by:

How would you rate the quality of this content?
Poor -----------------------------------------> Outstanding

Tell us why you rated the content this way. (optional)