Many ASP.NET developers using VB .NET will be coming to this environment with some VB6, VBA, or VBScript development experience. Although Visual Basic in its various "flavors" has supported its own mechanism for handling errors for as long as "Visual" has been attached to the title, the techniques available to V0o0iuB developers have never seemed fully fleshed out. In planning for exception handling in .NET, it's useful to contrast the new features with those many developing in ASP.NET are accustomed to using. (Listing 12.1 demonstrates a simple VB6 procedure with standard error-handling code in place.) Several issues surrounding VB's error handling have caused much complaining among VB developers, both experienced and novice:
VB6 requires you to jump around within procedures in order to handle errors. The On Error Goto, Resume, and Resume Next statements all involve jumping either forward or backward in code. The standard VB6 error-handling techniques involve at least two jumps within a procedure (one forward to the error-handling block, and a second back to a common procedure exit point).
If you follow good programming practices in VB6, including ensuring that your procedures have only a single exit point, the most convenient place to put that exit point is in the middle of your procedures (before the error-handling block). It is all too easy to forget the important Exit Sub or Exit Function.
VB6 provides no way to "push" and "pop" error handlers. If you want to preserve the current error trap, set up a different one, and later return back to the first, you must remember to include the correct On Error Goto… statement every time you want to change handlers.
VB6 includes only a single Err object. If an error occurs and you don't handle it immediately, you may permanently lose the error information before you get a chance to handle the error.
VB6's documentation includes almost no coverage of the types of errors (that is, the error numbers) you might receive due to an action you've taken in your code. Your only recourse is to experiment, see what error numbers you can generate by triggering errors while testing, and then trap those specific errors in your code.
Listing 12.1 Error Handling in VB6 Required at Least One Jump, and Often More
Sub TestVB6() On Error GoTo HandleErrors ' Do something in here that ' might raise an error. ExitHere: ' Perform cleanup code here. ' Disregard errors in this ' cleanup code. On Error Resume Next ' Perform cleanup code. Exit Sub HandleErrors: Select Case Err.Number ' Add cases for each ' error number you want to trap. Case Else ' Add "last-ditch" error handler. MsgBox "Error: " & Err.Description End Select Resume ExitHere End Sub
In addition, although VB developers are perfectly capable of using the Err.Raise method to raise errors back to calling procedures, this technique has never become a standard. Many developers creating code that is called by others simply return an error value to indicate success or failure, instead of raising an error upon failure. Because it's possible (and easy) to simply disregard error values returned from procedures you call, in too many cases, code that fails for any reason at runtime never raises the appropriate errors back to its callers.
Structured exception handling is a standard technique of managing faults that occur within applications. In general, this technique allows you to create blocks of code that work together to manage runtime error trapping, error detection, and error propagation within applications. With the addition of structured exception handling in VB .NET, it's easier for developers to manage error notification, raise errors, and determine the cause of a runtime error. Structured exception handling provides several advantages over the previous error-handling techniques used in VB6:
Error handling in .NET is based on the Exception class, which means you can obtain from it information about the current error as well as a linked list of errors that may have triggered it.
You can inherit from the Exception class, creating your own exceptions that have the same functionality as the base class, or extended functionality, as necessary. Because your code can trap for specific exceptions, creating your own exception class gives you a lot of flexibility.
Because every class in the .NET Framework throws exceptions when it encounters runtime errors, developers will get in the habit of trapping for exceptions and handling them. This makes it more likely that exceptions you throw from within your components will be successfully handled.
You can nest Try/Catch blocks within the Try, Catch, and Finally blocks. This gives you the capability of managing exception handling to any level of granularity that you require.
Listing 12.2 shows the layout of a simple exception handler in VB .NET. The following sections describe, in detail, how to use each of the keywords shown in Listing 12.2, and how to make use of the Exception class in tracking and raising errors.
Listing 12.2 Error Handling in VB .NET Doesn't Require Jumping Around
Sub TestVBNET() Try ' Do something in here that ' might raise an error. Catch ' Handle exceptions that occur within ' the Try block, here. Finally ' Perform cleanup code in here. End Try End Sub
You can mix old-style VB6 error handling with .NET structured exception handling in the same project, but not within the same procedure. On Error and Try can't exist within the same procedure.