JavaScript EditorJavascript debugger     Javascript examples


Team LiB
Previous Section Next Section

Error Handling

In any application, one challenge faced by developers is dealing with the inevitable errors. Application errors come in three varieties:

One thing all three types of errors have in common is that they must all be handled in some fashion, lest they provoke grave dissatisfaction on the part of your users. An important first step is prevention.

Selecting C# as your language to develop ASP.NET pages is the first step in eliminating some classes of errors that have plagued classic ASP applications. A properly compiled ASP.NET application will not contain undeclared variables or method calls that will compile correctly but could fail with type violations at runtime.

Ways to Handle Exceptional Situations

No matter how careful you are when developing an application, eventually there will be a situation that your application is not prepared to handle. For instance, your application might request access to a database when the database is unavailable. There are two general ways to react to this situation in C#:

  • Check return codes from methods that could fail

  • Use Structured Exception Handling

Checking return codes to all methods is the way that COM implemented error handling. Checking for HRESULT was a significant part of any COM program written in C or C++. C# allows Structured Exception Handling, where the flow of control is more straightforward. Exception handling brackets the section of code, allowing explicit handling of specific types of exceptions, as well as code that will always run, regardless of whether an exception occurs.

Checking Return Values

Checking return values seems initially to be the easiest way to handle errors. You can, in a very straightforward way, know exactly what failed and react to it in code very close to where the error occurs. The problems that occur are:

  • The error handling code interrupts the clean flow of what is happening in the normal case where the process proceeds without error.

  • It is too easy to forget about checking for error return codes.

  • Given a large number of operations that require checking, the level of nesting can become ungainly.

For example, the code to check three levels of return values shows how confusing this kind of error handling can get:

if ( OpenDB() == NO_ERROR   if ( OpenTable() == NO_ERROR   if ( FetchRow() == NO_ERROR   // Actually do something   }

This type of error handling is best suited for the sort of errors that would occur often. For instance, if you are prompting a user for the name of a file, the method that does that might best be handled by checking a return code.

Using Structured Exception Handling: try…catch…finally

The try…catch…finally form of exception handling, also known as structured exception handling, should be familiar to C++ and Java developers. In C#, the try…catch…finally syntax enables you to enclose code that can cause an exception in such a way as to catch and deal with specific exceptions and/or provide generic exception handling. The following code shows a simple try…catch block:

int a, b; // declare two ints, a and  double c try // Start monitoring for exception  //Code that may cause an exceptio a = 1 b = 0 c = a / b  catch ( DivideByZeroException   // Code to handle divide by 0 exceptio  finall  // Code that executes after any code in the Catch block(s }

You can define catch blocks for as many specific errors as you want to handle. The finally block can be used for any code you want to run after the exception- handling code, including cleanup code, such as code to close a file. The finally block of code is always run, whether or not an exception has occurred.

In addition to catching exceptions, your code can actually throw an exception. To do so, you use the throw keyword. For example, if you wanted to catch only the divide by 0 exception and then rethrow any other exception, you could use the following code:

int a, b double c try // Start monitoring for exception  //Code that may cause an exceptio a = 1 b = 0 c = a / b  catch ( DivideByZeroException   // Code to handle divide by 0 exceptio  catch ( Exception e   throw(e);// Rethrow exception   finall  // Code that executes after any code in the Catch block(s }

One thing worth noting is that in the second catch block, rather than just declaring the exception type, I specify an instance of the exception that I can then manipulate. In this example, I get a named instance of the exception so that I can rethrow it. This can also be useful when you have exceptions that contain details that you need to look at to properly handle the exception. It is also worth noting that the most specific catch blocks should be first, followed by any more general catch blocks. If the catch for the most general exception type (Exception in this example) was first, all exceptions would be caught in that block, including the more specific exception, the DivideByZeroException.

What happens if an exception is thrown and your code does not catch it? Probably not what you would like. This next example will step you though the process of creating a page that generates an unhandled exception, and then adding exception handling to properly handle the exception.

Add Exception Handling

  1. Open Visual Studio .NET if it’s not already open.

  2. If Chapter_03 is not already open, on the File menu, choose Open, and then click Project. Click the project Chapter_03 created earlier in this chapter. This project can also be selected by pointing to Recent Projects on the File menu and clicking the project.

  3. Right click the Chapter_03 project in the Solution Explorer on the right side of the screen. On the shortcut menu, choose Add, and click Add Web Form. When prompted, type the name of the form as Exceptions.aspx, and click the Open button.

  4. Position the mouse pointer over the Toolbox until it expands. Drag a Button control from the Toolbox onto the form. Drag a label onto the form just below the button.

  5. In the Properties pane on the right side of the screen, change the text of the button from Button to Divide By Zero, and click Enter. The button conveniently expands to show all the entered text.

  6. Change the ID of the label from Label1 to Message. The screen should look like the following illustration.

    Click To expand
  7. Double-click the button in the designer, and you will see the code view showing the Button1_Click event handler.

  8. Add the following code to the handler:

    int divisor = 0 Message.Text = (4/divisor).ToString();
  9. On the File menu, click Save All to save the page, and then on the Build menu, click Build Chapter_03 to compile the application.

  10. Browse the page by right-clicking it in Solution Explorer, and then selecting View In Browser (or Browse With). When you see the screen with the Divide By Zero button, click the button. You will see a screen similar to the following illustration, in which the Output window is closed to allow you to see more of the error page.

    Click To expand
  11. Close the application. Find the Button1_Click event handler and change the code to the following:

    int divisor = 0 tr  Message.Text = (4/divisor).ToString()  catch(DivideByZeroException  Message.Text = "Cannot divide by 0!" }
  12. On the File menu, click Save All to save the page, and then on the Build menu, click Build Chapter_03 to compile the application.

  13. To run the application, on the Debug menu, click Start, click the Divide By Zero button and the Message label will display a message telling you that you cannot divide by 0.

You’ll see more examples of exception handling throughout the book.


Team LiB
Previous Section Next Section


JavaScript EditorJavascript debugger     Javascript examples