420 Chapter 9 • Debugging ASP.NET
is known as widening. Narrowing is dangerous and could possibly result in runtime errors.
VB.NET supports the Option Strict statement to ensure that only widening conversions are allowed, otherwise it will generate an error message. Modifying our codes, we get:
Option Strict On
...
...
Dim shortNum As Int16
Dim intNum As Int32
...
shortNum = intNum
In this case, our compiler will generate an error message to indicate that such a conversion is not allowed.
The Option Strict On statement must be placed at the first line of your program. Using the Option Strict On also implies Option Explicit On (the Option Explicit statement ensures that variables are declared prior to usage).Thus undeclared variables would also generate error messages.
NOTE
In VB6, the array index can be changed using the Option Base statement. In VB.NET, the Option Base statement is not supported.
Runtime Errors
Runtime errors occur during the time when the application is running and something unexpected occurs. It happens regularly in projects that have very tight deadlines. Programmers stretched to their limits are often satisfied that their program runs.They do not have the time to carefully consider all the different possible scenarios in which their programs may be used, hence the result is often a buggy program.To ensure that an application is as robust and bug-free as possible, it is important to place emphasis on anticipating all the errors that can occur in your program.
Debugging ASP.NET • Chapter 9 |
421 |
Error handling got a new lease on life in the .NET Framework, particularly within the .NET languages. In VB6, error handling was unstructured, done using the primitive On Error statement. In the .NET languages, specifically in VB.NET, error handling can both be structured and unstructured.We will examine the two modes of handling errors in the next section.
Unstructured Error Handling
Using our previous example on narrowing conversions (assuming we use the Option Strict off statement), the following codes will trigger a runtime error:
Dim shortNum As Int16
Dim intNum As Int32
intNum = 999999
shortNum = intNum ' narrowing will fail!
You should see the error as shown in Figure 9.2.
Figure 9.2 Runtime Error
To prevent the error from happening,VB.NET supports the unstructured On Error statement:
Dim shortNum As Int16
Dim intNum As Int32
On Error Resume Next
422 Chapter 9 • Debugging ASP.NET
intNum = 999999
shortNum = intNum ' narrowing will fail!
If Err.Number <> 0 Then
Response.Write(Err.Description)
End If
The On Error Resume Next statement ignores any error that happens and continues as though no error has occurred.The error information is contained within the Err object. If an error has occurred, the property Number of the Err object would contain a nonzero value.The Description property will contain the description of the error. Some common errors and their descriptions are shown in Table 9.1.
Table 9.1 Common On Error Statements and Descriptions
On Error Statement |
Description |
|
|
On Error Resume Next |
Specifies that in the event an error occurs, resume |
|
execution. |
On Error Goto –1 |
Disables enabled exception in the current subroutine |
|
and resets it to Nothing. |
On Error Goto 0 |
Disables error handling. |
On Error Goto label |
Specifies the location to jump to when an error |
|
occurs. |
The following codes show an extended example outlining use of the On Error statement:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
On Error Goto ErrorHandling
Dim shortNum As Int16
Dim intNum As Int32
intNum = 999999
shortNum = intNum ' error #1 will be trapped
On Error Resume Next
shortNum = intNum ' error #2 will be ignored
Debugging ASP.NET • Chapter 9 |
423 |
On Error Goto 0
shortNum = intNum ' error #3 will cause program to fail
Exit Sub ' exits the subroutine
ErrorHandling:
If Err.Number <> 0 Then
Response.Write(Err.Description)
End If
Resume Next
End Sub
In the preceding example, we examine three errors.The first error will cause the execution to jump to the ErrorHandling block and after the error description has been printed, it resumes execution at the point it was interrupted.The second error will be ignored while the third error will cause the program to fail.
As you can see, unstructured error handling makes your code messy and difficult to debug, and also affects future maintenance. Hence, the recommended way to handle errors is to use structured error handling, which is covered in the next section.
Structured Error Handling
Using unstructured error handling usually results in messy and difficult-to-main- tain codes. Rather than placing an On Error statement at the beginning of a block to handle potential errors, .NET supports structured error handling using the Try-Catch-Finally construct. Structured error handling uses the Try-Catch-Finally construct to handle exceptions.The Try-Catch-Finally construct allows developers to actively “catch” different forms of errors and respond to them appropriately. It has the following syntax:
Try
'Executable statements that may cause
'an exception.
Catch [optional filters]
'Catches the error and responds to it Catch [optional filters]
'Catches the error and responds to it [Additional Catch blocks]
424 Chapter 9 • Debugging ASP.NET
Finally
' Always executed, with or without error
End Try
Rewriting our codes using structured error handling, we get:
Dim shortNum As Int16
Dim intNum As Int32
intNum |
= 999999 |
|
Try |
|
|
shortNum = intNum |
' narrowing will fail! |
Catch |
anyException As |
Exception |
Response.Write(anyException)
End Try
When executed, the error message printed is:
System.OverflowException: Exception of type System.OverflowException was thrown. at WebApplication1.WebForm1.Page_Load(Object sender, EventArgs e) in C:\Documents and Settings\lwm\VSWebCache\LWM\WebApplication1\ WebForm1.aspx.vb:line 31
When the line in the Try block is executed, it generates an exception, which is then caught by the Catch block.The statement in the Catch block prints out the reason for causing that exception.
The previous example doesn’t really do justice to the structured error-han- dling construct in VB.NET. Consider the following revised example:
Dim shortNum As Int16
Dim intNum As Int32
intNum = 999999 |
|
Try |
|
shortNum = intNum |
' narrowing will fail! |
Catch outofMemoryException As System.OutOfMemoryException
Response.Write("Out of memory!")
Catch overflowException As System.OverflowException
Debugging ASP.NET • Chapter 9 |
425 |
Response.Write("Overflow!")
Catch anyException As Exception
Response.Write("Some exception!")
End Try
Here we have multiple Catch statements. Each Catch statement tries to catch the different kinds of exceptions. If discovered, the exception is evaluated from top to bottom. Once a match is found, the codes within the Catch block are executed. If no match is found, an error message is displayed.
The three exceptions in the preceding list include:
■OutOfMemoryException Thrown when there is not enough memory to continue the execution of a program.
■OverflowException Thrown when an operation results in an overflow condition.
■Exception The base class for exception.This means all unmatched exceptions would be matched here.
When the statement within the Try block generates an exception, the few Catch statements are evaluated in order. First, it compares with the initial Catch block and checks to see if it matches the kind of exception specified in the Catch statement. If it doesn’t, it will compare it with the next, and so on. It only stops when a match is found. In our case, the exception is an overflow exception and hence the second Catch block is matched. If no match is found, an error message will be generated.
Lastly, the Finally block allows you to perform whatever cleaning up operation codes need doing, regardless of whether the exception occurs.
...
Catch anyException As Exception 'Response.Write(anyException) Response.Write("Some exception!")
Finally
'---codes here are always executed '---regardless of the exception
End Try
426 Chapter 9 • Debugging ASP.NET
NOTE
You cannot use both structured and unstructured error handling in the same subroutine.
Logic Errors
Logic errors are the most difficult problem to solve! While the previous errors can be taken care of with the help of special language constructs and the compilers, logic errors cannot be resolved so easily. Logic errors result when a piece of code does not work as intended. As an example, consider the following code snippets:
Dim i, factorial As Integer
For i = 1 To 5
factorial *= i
Next
Response.Write(factorial)
The code is trying to calculate the factorial of a number.Though there are no syntax errors, the code is not producing the expected answer (120). In fact, no result is printed. Only through some tracing and checking is it found that the culprit is actually forgetting to initialize the value of the factorial.To facilitate the debugging of logic errors, ASP.NET provides tracing ability.We will elaborate on the tracing feature available in ASP.NET in the next section.
Page Tracing
During the development stage, you may often need to monitor the value of some variables or functions, especially if they are not giving the correct results.Tracing through the codes is another important debugging method to make sure your codes flow in the intended manner.
ASP.NET provides tracing ability to easily map the flow of an application. In ASP, debugging is a painful process.You must often use the Response.Write() method to output the values of variables:
Dim i As Integer
Dim factorial As Integer
Debugging ASP.NET • Chapter 9 |
427 |
factorial = 1
For i = 1 To 5
factorial *= i
Response.Write("value of i is " & i & "<br>")
Response.Write("value of factorial is" & factorial &
"<br>")
Next
Response.Write(factorial)
How often have you forgotten to remove the debugging statements after you have tracked the error and deployed your application?
Using the Trace Class
ASP.NET includes the Trace class to help trace the flow of an application. Instead of using the Response object for debugging, we now get:
factorial = 1 For i = 1 To 5
factorial *= i
Trace.Write("value of i is " & i)
Trace.Write("value of factorial is" & factorial)
Next
Trace.Write(factorial)
Response.Write("The factorial of 5 is " & factorial)
To activate the trace, the page directive needs to have a Trace attribute with its value set to “true,” as shown in Figure 9.3. By just changing the value of the Trace attribute, we can turn tracing on or off.When the application is ready for deployment, simply set the Trace attribute to the value “false.”There is no need to remove the Trace statements in your application.
When the ASP.NET application is run, the following output is shown (Figure 9.4).Table 9.2 contains the following sections of the Trace page (not all are shown in Figure 9.4).
428 Chapter 9 • Debugging ASP.NET
Figure 9.3 Enabling Tracing
Figure 9.4 Displaying the Trace Information
|
Debugging ASP.NET • Chapter 9 |
429 |
Table 9.2 Sections in a Trace Page |
|
|
|
|
Sections |
Description |
|
|
|
|
Request Details |
Describes information pertaining to the request |
|
|
(e.g., SessionID, Encoding, and time of request). |
|
Trace Information |
Contains detailed information about the application |
|
|
currently running. Trace information is displayed in |
|
|
this section. |
|
Control Tree |
Displays information about controls used in a page |
|
|
and the size of the Viewstate hidden field. |
|
Cookies Collection |
Displays the cookie set by the page and its value. |
|
Headers Collection |
Displays HTTP header information like content length |
|
|
and user agent. |
|
Forms Collection |
Displays the name of controls in a page and its value. |
|
Server Variables |
Displays the environment variables on the server side. |
|
Notice that our Trace message is written under the “Trace Information” section. The Trace class contains the following members (Table 9.3 and Table 9.4).
Table 9.3 Properties in the Trace Class
Property |
Description |
|
|
IsEnabled |
Indicates whether tracing is enabled for the current request. |
TraceMode |
Sets the trace mode: sortByCategory or sortByTime. |
|
Table 9.4 Methods in the Trace Class |
|
|
Methods() |
Description |
|
|
Warn |
Writes the trace information in red. |
Write |
Writes the trace information. |
For example, the Warn() method of the Trace class causes the Trace information to be printed in red as shown in Figure 9.5 (all the nonshaded lines you see are displayed in red).
For i = 1 To 5
factorial *= i
Trace.Warn("value of i is " & i)