Home
    Shop
    Advertise
    Write For Us
    Affiliate
    Newsletter
    Contact

ASP.NET Code Debugging

There are several kinds of mistakes you can make when you coding, no matter how skilled you are. It can be very hard to track down the problem in your code. Fortunately the .NET Framework SDK includes a lightweight debugger that is perfectly suited for this task. Together with Tracing and Exception Handling you're armed and ready.

 

There are several kinds of mistakes you can make. The first group of mistakes is the easiest one to find: syntax errors. These are errors against the syntax of a particular programming language (in this case C#). Visual Studio underlines syntax errors at design time and provides a tooltip with some extra explanation. If you happen to miss out an error and try to compile, you'll get an Error List (or View > Error List) with all the errors in it. Double clicking an error will bring you to the line that has to be corrected.

The second group of mistakes is logic errors. Logic errors will not cause the program to stop working, but it can produce incorrect data that may not be immediately recognizable. The mistake could be a logical error in a statement, algorithm or even selecting the wrong method. To debug these type of errors you'll have to output the program's variables to a file or on the screen. It might even be necessary to place breakpoints and run through the code line by line.

The last group of mistakes is runtime errors. Runtime errors will cause the program to stop working. Some of these errors will have to be repaired (e.g. null pointers) and others should be cought with Exception Handling (e.g. parse error in a string when you want an integer).

Debug configuration

To enable debugging you'll have to add following line between the configuration tags in your Web.config file:
<compilation debug="true" />

If you didn't add the line to your Web.config file yet, Visual Studio will ask to do it for you the first time you hit F5 (or Debug > Start Debugging). Be sure to disable this setting when you put your Web site in production because it can significantly affect application performance.

Breakpoints

A breakpoint is a line in your code where the execution of the application is temporarily interrupted. Note that the program is interrupted just before that line is executed, not just after. To place a breakpoint click in the Margin Indicator bar next to the line of code or select the code and hit F9 (or Debug > Toggle Breakpoint). When you hit F5 to debug, the application will halt at the breakpoint.

It is possible to assign advanced settings to a breakpoint by opening the breakpoints window (Debug > Windows > Breakpoints). You can assign a condition under which the breakpoint is hit when the breakpoint location is reached. If the expression is true or has changed then the application will interrupt, otherwise it will continue. Another possibility is counting the number of breakpoint hits and break at a certain number (or multiple of that number) or each time after a certain amounts of hits has been let through. It's also possible to print a message or run a macro with these advanced breakpoints.

Break mode commandos

Here's a list of useful commandos available on the toolbar and in the Debug menu while in break mode:

  • Start/Continue (F5, Debug > Start): start or continue executing

  • Stop Debugging (Shif+F5, Debug > Stop Debugging): completely stop debugging/executing

  • Restart (Ctrl+Shift+F5, Debug > Restart): restart from the beginning

  • Step into (F11, Debug > Step into): execute the code line by line

  • Step over (F10, Debug > Step over): execute current procedure line by line but don't step into called procedures

  • Step out (Shift+F11, Debug > Step out): execute whole procedure at once

Debugging windows

Break mode is often used to print and follow values of the variables and expressions. This can be done in several ways, only a few will be explained here. The easiest way is to hover over the variable and it will show the current assigned value and most of the time extra properties (hidden under a + sign).

The first real window is the Quick Watch which shows up with Ctrl+Alt+Q (or Debug > Quick Watch). In this window it's possible to quickly check and if needed change the value of a variable. It's also possible to add another variable or calculate an expression.

The Autos Window (Ctrl+Alt+V,A or Debug > Windows > Autos) shows the variables in the active statement and the previous code line. The Local Window (Ctrl+Alt+V,L or Debug > Windows > Locals) shows the variables in the current procedure/form. You never know you'll find your mistake while checking the flow of the program. For this purpose you have access to the Call Stack Window (Ctrl+Alt+C or Debug > Call Stack) which follows the flow of the program and shows info on every function call. Every single window has his strengths in certain cases. It's up to you to choose the right window for the right job.

Trace

Trace is a performance tool that gives you better sight on how a page works. In the trace log you can find everything that has to do with the current page covering things like execution time, every single control with their hierarchy and viewstate, header collections and server variables. And next to all of this you can add your own comments in the trace log thanks to Trace.Write() and Trace.Warn(). This might be useful to see what happens between two of your own comments.

You can activate Trace on page level by adding Trace=true in the page directive or on application level with the following lines in your web.config file:

<configuration>
  <system.web>
    <trace enabled="true" localOnly="true"/>
  </system.web>
</configuration>

In the picture below you can see the source of a button click event where output to the trace log is added at the top and the bottom of the event code. Underneath the source code fragment you have a part of the trace log itself as it is generated after you clicked the button. You notice both entries in the trace log that were created by the code.

protected void btnBereken_Click(object sender, EventArgs e)
{
    Trace.Write("btnBereken.click", "About to update the label");
    int x;
    x = int.Parse(txtGetal.Text);
    for (int i = x; i >= 0; i--)
        x *= i;
    lblResultaat.Text = PrintText(x.ToString());
    Trace.Warn("btnBereken.click", "Label updated");
}

Exception Handling

No matter what you do, some errors will always have a chance to occur (e.g. error if you want to parse an integer out of a textbox and the user enters a normal string or even an invalid number). The last thing you want is to show those errors to the user so you'll have to handle all the possible exceptions. This can be done on several levels.

The first place where you should handle exceptions is where you generate them yourself (by throwing a new exception) or where you know exceptions are very possible to occur (divide by 0, missing database link, ...). This is simply done by adding try/catch/finally around the dangerous code fragments. The finally part is optional and is used in case you want something to happen no matter if there is an exception or not.

But be prepared! Some exceptions are totally unexpected or you just forgot one of the possible exceptions while handling the rest. You can catch these on page level by overriding the standard OnError event. After handling the exception and maybe generating some output to a log or the screen you can kill the error and prevent it to go further to application level with Server.ClearError().

protected void btnBereken_Click(object sender, EventArgs e)
{
    int x;
    try
    {
        x = int.Parse(txtGetal.Text);
        for (int i = x; i >= 0; i--)
            x *= i;
        lblResultaat.Text = PrintText(x.ToString());
    }
    catch (OverflowException ex)
    {
        lblResultaat.Text = "Number to big!";
    }
}
 
protected override void OnError(EventArgs e)
{
    Exception objErr = Server.GetLastError().GetBaseException();
    string err = "Error Caught in Application_Error event\n" +
                      "Error in: " + Request.Url.ToString() +
                       "\nError Message:" + objErr.Message.ToString();
    Response.Write(err.ToString());
    //Server.ClearError();   // kills the exception
    // forward to application level
}

The last level to catch exceptions is the application level. You might choose to drop out the Server.ClearError() on page level to forward the exception to the application level. This can be useful if you want to write the error in a log or event log file and mail the administrator that an unexpected error has occurred. All these possibilities can be implemented in Global.asax (known as the ASP.NET application file).

    void Application_Error(object sender, EventArgs e)
    {
        using (StreamWriter w = File.AppendText(Server.MapPath("log.txt")))
        {
            w.WriteLine("\r\nLog Entry : ");
            w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
                DateTime.Now.ToLongDateString());
            Exception objErr = Server.GetLastError().GetBaseException();
            string err = "Error in: " + Request.Url.ToString() +
                          ". Error Message:" + objErr.Message.ToString();
            w.WriteLine(err);
            w.WriteLine("__________________________");
            w.Flush();
         }   
    }

Using this method you might consider adding some user-friendly error pages since you don't want them to get stuck in the generated error page. It also looks more professional if you warn the user with a nice message like "There has been an unexpected error, the administrator has been informed. Please try again later." You can create this error page yourself and by adding some extra code to your Web.config file your site can crash with style.

<customErrors  mode="On"  defaultRedirect="~/Error.aspx">
  <error statusCode="404" redirect="~/Error.aspx?code=404" />
  <error statusCode="408" redirect="~/Error.aspx?code=408" />
  <error statusCode="505" redirect="~/Error.aspx?code=505" />
</customErrors>

 

You can download Sample Debugging Example Application used in this tutorial

This tutorial is written by Assesino


Tutorial toolbar:  Tell A Friend  |  Add to favorites  |  Feedback  |   


comments powered by Disqus