Recipe 8.2. Handling Errors at the Method Level


Problem

You're uncertain how to organize your code to handle errors at the method level. In particular, you'd like to take advantage of .NET structured exception handling for dealing with errors, but you're unsure how to best implement it.

Solution


If potential errors are recoverable in the routine

Use a combination of try…Catch blocks as a retry mechanism for error handling.


If useful information can be added to the exception

Create and throw a new exception with the added information.


If cleanup is required

Perform it in the finally block.


If potential errors are not recoverable in the routine

Recovery should be handled by the calling routine and its error-handling structure.

Discussion

Because .NET structured exception handling is so good, we recommend you use it, or consider using it, with every method that you write. There are a number of ways to implement its functionality.

Basic syntax of Try…Catch…Finally

To begin with, here is the syntax of a .NET try…Catch…Finally block in VB and C#:

 

Private Sub anyRoutine( ) Try 'Routine code in this block Catch exc As Exception 'error handling in this block Finally 'cleanup performed in this block End Try End Sub 'anyRoutine

private void anyRoutine( ) { try { // Routine code in this block } catch (Exception exc) { // error handling in this block } finally { // cleanup performed in this block } } // anyRoutine

The try block includes code that implements the method.

The catch block, which is optional, includes code to handle specific errors that you have identified as likely to occur and to recover from them when that is possible.

The finally block code, which is optional, performs any cleanup required on leaving the method, whether due to an error or not. This typically includes the closing of any open database connections and files, disposing of objects created by the method, and so on. A finally block is guaranteed to be executed even if an exception is thrown or the code in the routine performs a return.

As noted, the catch and finally blocks are optional. Sometimes, you'll want to use one or the other, and other times you'll want to use both.

A try block must contain either a catch or a finally block.


Guidelines for implementing

Developers should make use of .NET exception handling in any method where an error is possible, but the exact technique depends on the circumstances, as summarized in Table 8-1.

Table 8-1. Guidelines for Try…Catch…Finally blocks

Can errors occur?

Recoverable?

Can useful context information be added?

Cleanup required?

Recommended combination of try, catch, and finally

No

N/A

N/A

No

None

No

N/A

N/A

Yes

TRy and finally only

Yes

No

No

No

None

Yes

No

No

Yes

TRy and finally only

Yes

No

Yes

No

try and catch only

Yes

No

Yes

Yes

try, catch, and finally

Yes

Yes

N/A

N/A

try and catch only


The .NET Framework does not close database connections, files, etc., when an error occurs. This is your responsibility as a programmer, and you should do it in the finally block. The finally block is the last opportunity to perform any cleanup before the exception-handling infrastructure takes control of the application.


Additional considerations

To help you implement error handling in a routine, we've provided the following leading questions. Your answers can help you determine what portions of the try…Catch…Finally block you need. Refer to Table 8-1 for how to structure a routine based on your answers.


Can any errors occur in this routine?

If not, no special error-handling code is required. Do not shortchange the answer to this question, however, because even x=x+1 can result in an overflow exception.


Are the potential errors recoverable in the routine?

If an error occured but nothing useful can be done in the routine, the exception should be allowed to propagate to the calling routine. It serves no useful purpose to catch the exception and rethrow it. This question is different from, "Are the potential errors recoverable at the application level?" For example, if the routine attempts to write a record to a database and finds the record locked, a retry can be attempted in the routine. However, if a value is passed to the routine and the operations on the value result in an overflow or other error, recovery cannot be performed in the routine but should be handled by the calling routine and its error-handling structure.


Can any useful information be added to the exception?

Exceptions that occur in the .NET Framework contain detailed information regarding the error. However, the exceptions do not provide any context information about what was being attempted at the application level that may assist in troubleshooting the error or providing more useful information to the user.

A new exception can be created and thrown with the added information. The first parameter for the new exception object should contain the useful context message, and the second parameter should be the original exception. The exception-handling mechanisms in the .NET Framework create a linked list of Exception objects to create a trail from the root of the exception up to the level where the exception is handled. By passing the original exception as the second parameter, the linked list from the root exception is maintained, as in this example:

 

Catch exc As Exception Throw New Exception("Useful context message", _ exc)

catch (Exception exc) { throw (new Exception("Useful context message", exc)); }


Is a combination of Try…Catch blocks warranted?

A combination of TRy…Catch blocks can help provide a retry mechanism for error handling, as shown in Examples 8-1 (VB) and 8-2 (C#). These examples show the use of an internal try…Catch block within a while loop to provide a retry mechanism and an overall TRy…Finally block to ensure cleanup is performed.

The catch block should not be used for normal program flow. Normal program flow code should only be placed in the TRy block, with the abnormal flow being placed in the catch block. Using the catch block in normal program flow will result in significant performance degradation due to the complex operations being performed by the .NET Framework to process exceptions.


The exception-handling mechanisms in the .NET Framework are powerful. Whereas this example highlights exception handling at the method level, other specific exception types can be caught and processed differently. In addition, you can create new exception classes by inheriting from the base exception classes and adding the functionality required by your applications. An example of this technique is shown in Recipe 8.4.

See Also

Recipe 8.4

Example 8-1. Retrying when an exception occurs (.vb)

 Imports System Imports System.Configuration Imports System.Data Imports System.Data.OleDb … Private Sub updateData(ByVal problemID As Integer, _    ByVal sectionHeading As String) Const MAX_RETRIES As Integer = 5 Dim dbConn As OleDbConnection = Nothing Dim dCmd As OleDbCommand = Nothing Dim strConnection As String Dim cmdText As String Dim updateOK As Boolean Dim retryCount As Integer Try 'get the connection string from web.config and open a connection 'to the database strConnection = ConfigurationManager. _ ConnectionStrings("dbConnectionString").ConnectionString dbConn = New OleDbConnection(strConnection) dbConn.Open( ) 'build the update SQL to update the record in the database cmdText = "UPDATE EditProblem " &_   "SET SectionHeading='" & sectionHeading & "' " &_   "WHERE EditProblemMaximum retries exceeded", _ exc) End If End Try End While Finally 'cleanup If (Not IsNothing(dbConn)) Then dbConn.Close( ) End If End Try End Sub 'updateData 

Example 8-2. Retrying when an exception occurs (.cs)

 using System; using System.Configuration; using System.Data; using System.Data.OleDb; private void updateData(int problemID, String sectionHeading) { const int MAX_RETRIES = 5; OleDbConnection dbConn = null; OleDbCommand dCmd = null; String strConnection = null; String cmdText = null; bool updateOK; int retryCount; try { // get the connection string from web.config and open a connection // to the database strConnection = ConfigurationManager. ConnectionStrings["dbConnectionString"].ConnectionString; dbConn = new OleDbConnection(strConnection); dbConn.Open( ); // build the update SQL to update the record in the database cmdText = "UPDATE EditProblem " +   "SET SectionHeading='" + sectionHeading + "' " +   "WHERE EditProblemMaximum retries exceeded", exc); } } // catch } // While } // try finally { // cleanup if (dbConn != null) { dbConn.Close( ); } } // finally } // updateData 



ASP. NET Cookbook
ASP.Net 2.0 Cookbook (Cookbooks (OReilly))
ISBN: 0596100647
EAN: 2147483647
Year: 2003
Pages: 202

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net