try and catch


Sams Teach Yourself ASP.NET in 21 Days, Second Edition
By Chris Payne
Table of Contents
Day 20.  Debugging ASP.NET Pages

try and catch

Normally, when a piece of code causes an error, it stops your application and displays an error message, as shown when you tried to execute Listing 20.1. If it's at all possible to stop this error, you want to do so (after all, ideally, you should never see an error).

When you use a try statement, you tell ASP.NET that you want it to tentatively execute a block of code. If any of the code inside the try statement causes an error, instead of your application crashing and displaying the error, the execution continues and allows you to try to deal with the problem. For example, if you wrapped line 18 of Listing 20.1 in a try statement, you could have potentially stopped the error from crashing your application, and continued on with the rest of the code.

The try statement is used to guard a section of code that may cause errors. In traditional application development, this is a must because certain actions are expected to produce errors. For instance, although you may not know it, clicking the Cancel button on a dialog box typically causes an error, which the application must handle somehow. The try statement and its associated statements are known as structured exception handling.

As you've seen in a few examples throughout this book, the syntax for this statement is simple. It consists of a try statement, followed by the code to be guarded and a catch or finally statement. For example:

 'VB.NET 1:  'create OleDbCommand object here 2:  try 3:     objCmd.Connection.Open 4:     ... 5:  catch 6:     hander error 7:  end try //C# 1:  //create OleDbCommand object here 2:  try { 3:     objCmd.Connection.Open(); 4:     ... 5:  } catch { 6:     hander error 7:  } 

In this case, you guard the code between lines 2 and 5 because it can cause an error. If no errors occur inside the try block, the execution of code transfers to line 7 and the code continues as normal. If an error does occur, the execution of code moves to the catch statement on line 5, which will contain code to handle the error.


Let's examine the technical details more closely. When an error occurs in an ASP.NET application, an exception is thrown. This means that something has occurred that shouldn't have, and VB.NET or C# tosses an error in the air for someone to see. If you don't do anything about the exception, the error comes crashing down, along with your application, and the person who sees the error will be the end user.

Throwing exceptions allows you to intercept the error before it crashes the application and the user sees it. If you intercept it in time, you can prevent a crash and fix the problem.

Enter the try statement. When an error occurs, the try statement will alert its companion statement, catch, which will catch the exception and handle it. Listing 20.2 shows an example.

Listing 20.2 A Debugging Example
 1:  <%@ Page Language="VB" %> 2:  <%@ Import Namespace="System.Data" %> 3:  <%@ Import Namespace="System.Data.OleDb" %> 4: 5:  <script runat="server"> 6:     dim Conn as new OleDbConnection("Provider=" & _ 7:              "Microsoft.Jet.OLEDB.4.0;" & _ 8:              "Data Source=c:\ASPNET\data\banking.mdb") 9: 10:     sub GetData(Sender as Object, e as EventArgs) 11:        dim objCmd as OleDbCommand = new OleDbCommand _ 12:           ("select * from tblUsers where UserID = " & _ 13:           tbID.Text, Conn) 14:        dim objReader as OleDbDataReader 15: 16:        objCmd.Connection.Open() 17:        objReader = objCmd.ExecuteReader 18: 19:        dgData.DataSource = objReader 20:        dgData.DataBind() 21: 22:        objReader.Close 23:        objCmd.Connection.Close() 24:     end sub 25:  </script> 26: 27:  <html><body> 28:     <form runat="server"> 29:        <asp:Label  runat="server" 30:           maintainstate=false /><br> 31:        Enter an ID: <asp:TextBox  runat="server" 32:           AutoPostBack=True 33:           OnTextChanged=GetData /><p> 34:        <asp:DataGrid  runat="server" 35:           BorderColor="black" 36:           GridLines="Vertical" 37:           width="100%" 38:           Font-Name="Arial" 39:           Font-Size="8pt" 40:           HeaderStyle-BackColor="#cccc99" 41:           ItemStyle-BackColor="#ffffff" 42:           AlternatingItemStyle-Backcolor="#cccccc" 43:           AutoGenerateColumns="true" /> 44:     </form> 45:  </body></html> 


This is a simple page that returns user information based on the user ID. When you enter a number in the text box, the database commands are executed and bind the returned data to the DataGrid. However, what happens when you accidentally enter a letter instead? Figure 20.4 shows this situation.

Figure 20.4. The wrong user input causes an error.


This isn't a good thing to show users. Let's add a try statement to the listing to handle the error gracefully. Replace lines 16?3 with Listing 20.3.

Listing 20.3 Using a try Block with Listing 20.2
 16:  try 17:     objCmd.Connection.Open() 18:     objReader = objCmd.ExecuteReader 19: 20:     dgData.DataSource = objReader 21:     dgData.DataBind() 22: 23:     objReader.Close 24:     objCmd.Connection.Close() 25:  catch 26:     lblMessage.Text = "Invalid input!" 27:  end try 

Now request the page again. You should see what's shown in Figure 20.5.

Figure 20.5. Handling the error gracefully.


The try block caught the error before it caused problems and displayed an error message, as shown on line 26 of the previous code snippet. The execution then picked up after line 27 and was completed normally.

Exceptions are grouped hierarchically. The System.Exception class is the base exception and contains all other exceptions. Directly under Exception is SystemException, and under that are various others, such as OleDbException and FormatException. As you move down the hierarchy, the errors become more and more specific. For example, SystemException covers all built-in exceptions, but FormatException only covers the error caused by invalid user input. All these exceptions are .NET classes, just as the other objects we've been dealing with so far have been. Figure 20.6 shows an example of the exception hierarchy.

Figure 20.6. An example of the System exception hierarchy.



Note that although SystemException falls below Exception in the exception hierarchy, it still belongs to the System namespace. That is, you use System.SystemException and not System.Exception.SystemException.

Using a generic catch statement, as you did previously, catches all errors of every type. In other words, it catches any exception under the base Exception class. However, you can specify the types of errors you want to handle with this syntax:

 catch VariableName as ExceptionType 

For example, you could replace the previous listing with Listing 20.4.

Listing 20.4 A Revised try Block
 16:  try 17:     objCmd.Connection.Open() 18:     objReader = objCmd.ExecuteReader 19: 20:     dgData.DataSource = objReader 21:     dgData.DataBind() 22: 23:     objReader.Close 24:     objCmd.Connection.Close() 25:  catch objEx as FormatException 26:     lblMessage.Text = objEx.Message 27:  catch objEx as OleDbException 28:     lblMessage.Text = "Database error!" 29:  catch objEx as Exception 30:     lblMessage.Text = "Unknown error!" 31:  end try 

On line 25, you catch an exception of the type FormatException (as well as those below it). Don't worry about the Message property on line 26; you'll get to that soon. On line 27, you catch an OleDbException. And on line 29, you catch all exceptions. Because exceptions are hierarchical, a catch statement will handle the exception it declares, as well as all of the more-specific exceptions. Therefore, you should write catch statements in order of specificity, putting the less-specific exceptions last. When using catch statements, be aware of the following:

  • Derived exception classes (such as FormatException or OLEDBException) represent specific error scenarios that you are testing for due to the possibility that they could occur or that specific action might be required in those cases.

  • The try...catch structure stops evaluating exceptions after it encounters a catch block that applies.

  • Exception is the catch-all in this scenario, similar to case else in an if statement.

This listing produces what's shown in Figure 20.7.

Figure 20.7. Multiple catch statements catch more specific errors. Use the exception Message property to display the error text associated with the exception.


There's one more statement associated with the try statement: the finally statement. You can use this block to execute some clean-up code or other end processing, whether or not an exception occurs. You could insert the code in Listing 20.5 into Listing 20.2 to close your database connection no matter what happens.

Listing 20.5 Using the finally Statement
 16:  objCmd.Connection.Open() 17:  try 18:     objReader = objCmd.ExecuteReader 19: 20:     dgData.DataSource = objReader 21:     dgData.DataBind() 22: 23:     objReader.Close 24:  catch objEx as Exception 25:     lblMessage.Text = "Unknown error!" 26:  finally 27:     objCmd.Connection.Close() 28:  end try 

Figure 20.8 illustrates the process when using a try block.

Figure 20.8. The order of execution when using a try block.


Every exception class has a few properties that you can use to determine the cause of the error:

  • HelpLink?A NAME="idd1e110485"> A link to a file containing more information about the error (note that you must create the link and file yourself).

  • InnerException? A reference to an inner exception. If another exception was caught and passed to another exception handler, this returns the reference to the first exception.

  • Message? The message describing the exception.

  • Source? A string containing the name of the object that caused the error.

  • StackTrace? Returns a stack trace that specifies the cause of the error. (More about that in "Tracing" later today.)

  • TargetSite? The method that caused the error.

Throwing Exceptions

Exceptions are very useful, and they aren't only used for catching errors. In fact, there may be times when you want to throw your own custom exceptions.

For example, recall the Web Services you built on Days 16 ("Creating Web Services") and 17 ("Consuming and Securing XML Web Services"). Suppose that you're verifying information against a database and the validation fails. You could throw a custom exception in your service for the client application to handle with a try and catch.

To throw an exception, simply use the throw keyword:

 throw new Exception("I'm taking exception to that!") 

(The syntax is the same in C#.) This statement creates a new custom exception based on the Exception class. The string inside the parentheses is the error message. When you add this line to the beginning of the GetData method in Listing 20.1, you'll receive the page displayed in Figure 20.9 after you submit the form.

Figure 20.9. Using throw to cause a custom exception.


Throwing a custom exception can be very useful if you don't want to handle the exception yourself. As long as the function that called the code that produced the error can handle the exception, you don't have to worry about it.

For example, one case in which throwing a custom exception might be useful is when a user is entering input into a form. After the form has been posted, your post handler code calls a validation method that determines whether one of the entries is invalid (for instance, the user has entered a number instead of his name). The validation routine could throw a custom error to alert the calling method that an error has occurred. The calling method could then handle it as needed.

Note that you don't have to throw a custom exception you can throw an exception of any available type. For instance, the following throws an error specifying that a required parameter was missing:

 throw new ArgumentNullException() 

This is useful when you're building business objects, and it allows implementers to handle the errors as they see fit.

When to Use a try Statement

try statements are useful for debugging code, allowing you to discover errors without breaking execution. There are a few general rules you should follow when using try statements.

First, you should always use try when you're accessing systems outside of the ASP.NET environment when you're accessing databases or files, for instance. There are many factors you have no control over that can go wrong the file may not exist, the user may not have proper permissions to access the file, the database might be offline, the database table you're trying to access may have been deleted, and so on. Because of this, try statements are a must.

Use try blocks when you're unsure of code, especially for testing and debugging. For example, there may be times when you create code that depends highly on other factors in your application (binding to DataGrids is a perfect example).

Don't rely on try statements to catch user input errors. Instead, use another method, such as Validation controls, which are built specifically for this purpose. These controls provide a richer programming model for handling these errors and can pinpoint errors more precisely than try statements.

Finally, don't use try blocks for all of your code; use them only as necessary. The processing overhead that this statement introduces may be small, but it isn't always worth the expenditure.


    Sams Teach Yourself ASP. NET in 21 Days
    Sams Teach Yourself ASP.NET in 21 Days (2nd Edition)
    ISBN: 0672324458
    EAN: 2147483647
    Year: 2003
    Pages: 307
    Authors: Chris Payne

    Similar book on Amazon © 2008-2017.
    If you may any questions please contact us: