The following sections work through a series of examples, adding increasingly complex error-handling features to the sample code you've seen already. Starting with a scenario in which you've added no exception handling code at all, these examples introduce the concepts of trapping and identifying exceptions.
We'll use the terms exception handling and error handling to mean the same thing that is, code you add to a procedure so that it can manage runtime errors as they occur.
All the examples use the same basic premise: Your goal is to open a file, retrieve its length, and then close the file. Each example uses this code to do its job, retrieving the filename from a text box (txtFileName) on the sample form named Errors.aspx:
Dim lngSize As Long Dim s As FileStream s = File.Open(txtFileName.Text, FileMode.Open) lngSize = s.Length s.Close()
Of course, it's possible (for many reasons) that the code might fail. For example, the code will raise an exception if any of the following are true:
The file isn't found.
The path doesn't exist.
The drive containing the file isn't ready (perhaps you've requested the size of a file on a floppy drive that doesn't contain media).
You don't have permissions to access the file or folder.
You've specified an invalid filename.
The list could go on and on. All the following examples use some variation of this code in order to demonstrate features of structured exception handling.
In order to follow along with the discussion in this chapter, you'll need to open the sample project, Jumpstart\ErrorHandling\ErrorHandling.sln.
The sample application corresponding to this material, ErrorHandling.sln, includes a Web Form, Errors.aspx, that allows you to try out the various techniques described here (see Figure 12.1). For each case, try entering the path to a file that doesn't exist, a drive that doesn't exist, a drive that doesn't contain any media, or any other path that might trigger a file system error.
Figure 12.1. Use this sample Web Form to demonstrate all the different features discussed in this chapter.
The Base Case: No Error Handling at All
What happens if your code includes no exception handling at all? In that case, any errors that occur at runtime bubble back up to the .NET runtime, and the runtime will greet your users with a confusing and hard-to-read Web page, as shown in Figure 12.2. In order to avoid this page, should a runtime error occur, you'll need to add exception handling to at least your top-level procedures and to lower-level procedures as necessary.
Figure 12.2. Although this Web page may make sense to a programmer, an end user should never see it.
Just as in VB6, if you don't add exception handling to a procedure, and an error occurs within that procedure, the .NET runtime will pop the current procedure off the call stack and will return to the previous procedure. If that procedure includes error handling, the runtime will use that code. If not, the runtime continues to pop procedures off the stack until it backs out to a procedure that does include error handling. If no procedures include error handling, all the way back to the first-called procedure, the .NET runtime handles the error itself, as you saw in Figure 12.2.
Adding a Simple Try/Catch Block
In order to gracefully handle runtime errors, add a Try/Catch/End Try block around any code that you want to protect. If a runtime error occurs in the code within the Try block, execution will immediately continue with the code within the Catch block, as demonstrated in Listing 12.3.
Listing 12.3 The Simplest Structured Exception Handling Includes Try and Catch Blocks
Private Sub SimpleCatch() Dim lngSize As Long Dim s As FileStream ' This is better, but not much. You ' don't really have any idea what ' went wrong! Try s = File.Open(txtFileName.Text, FileMode.Open) lngSize = s.Length s.Close() Catch lblError.Text = "Error occurred!" End Try End Sub
When this code runs, rather than the application displaying the error page and halting, you'll see a simple "Error occurred" message appear in a label control on the page. To test this yourself, choose the Simple Catch option in the Error Handling combo box on the sample form.
If you add a Try/End Try block to your procedure, you'll need to include at least a single Catch block (you'll find more on including multiple Catch blocks later). If you want to disregard errors that occur, simply put nothing at all in the Catch block. This isn't a great idea, because simply disregarding errors can hide serious flaws in your application, but it will quietly disregard any errors that occur.
Determining What Happened
Once a runtime error occurs, how can you determine what error it is and how to deal with it? You can create a variable, declared As Exception, to retrieve error information for you. The Exception class provides information about the runtime error, as shown in Table 12.1.
Table 12.1. Useful Members of the Exception Class
|Member ||Description |
|HelpLink ||Links to the help file associated with this exception. |
|InnerException ||References the inner exception (the exception that originally occurred) if this exception is based on a previous exception. Exceptions can be nested. That is, when a procedure throws an exception, it can nest another exception inside the exception it's raising, passing both exceptions out to the caller. The InnerException property gives access to the inner exception. |
|Message ||Error message text. |
|StackTrace ||The stack trace, returned to you as a single string containing all the information about how you got to where you are in the code, at the point the error occurred. |
|TargetSite ||The name of the method that raised the exception. |
|ToString ||Converts the exception name, description, and the current stack dump into a single string. |
|Message ||Returns a description of the error that occurred. |
The Catch block includes the reference to the variable, like this:
Try ' Code that might trigger an exception. Catch exp As Exception ' Handle the exception, using exp, in here. End Try
You can also declare the Exception variable outside the Catch block:
Dim exp As Exception Try ' Code that might trigger an exception. Catch exp ' Handle the exception, using exp, in here. End Try
You might use code like what's shown in Listing 12.4 to trap an exception and display text indicating the problem that has occurred.
Listing 12.4 Use the ToString Method of the Exception Object to Display Error Information
' Simple Exception option on the sample form. Private Sub SimpleException() Dim lngSize As Long Dim s As FileStream ' Display the entire contents of the Exception object. Try s = File.Open(txtFileName.Text, FileMode.Open) lngSize = s.Length s.Close() Catch exp As Exception Error.Text=exp.ToString End Try End Sub
The name of the Exception variable isn't important. The sample code uses exp as the variable name, but that choice was arbitrary. If you find this name inconvenient in your own procedures, you may prefer to choose a different one.
If you simply want to display an error message, indicating the particular error that you've trapped, you can use the Message property of the Exception class, like this:
lblError.Text = e.Message
So far, you've seen how to trap an exception when it occurs and how to indicate to the user what went wrong. Most of the time, you'll also need to be able to take distinct action depending on the specific error that occurred. In VB6, this meant adding a Select Case block based on the active error number. In VB .NET, this involves adding additional Catch blocks for each error you'd like to trap individually. The next section digs into how you can add this functionality to your procedures.