For methods not marked with the AutoComplete attribute, you must:
- Call ContextUtil.SetAbort within the catch block to vote to abort the transaction. This sets the consistent flag to false.
- Call ContextUtil.SetComplete if an exception doesn't occur to vote to commit the transaction. This sets the consistent flag to true (its default state).
The following code illustrates this approach.
// Open the connection, and perform database operation
. . .
ContextUtil.SetComplete(); // Manually vote to commit the transaction
catch (SqlException sqlex)
LogException( sqlex ); // Log the exception details
ContextUtil.SetAbort(); // Manually vote to abort the transaction
// Exception is handled at this point and is not propagated to the caller
// Close the database connection
. . .
Note If you have multiple catch blocks, it is easier to call ContextUtil.SetAbort once at the start of a method, and call ContextUtil.SetComplete at the end of the try block. In this way, you do not need to repeat the call to ContextUtil.SetAbort within every catch block. The setting of the consistent flag determined by these methods has significance only when the method returns.
You must always propagate exceptions (or wrapped exceptions) back up the call stack because this makes the calling code aware that the transaction will fail. This allows the calling code to make optimizations. For example, in a bank funds transfer scenario, the transfer component could decide not to perform the credit operation if the debit operation has already failed.
If you set the consistent flag to false and then return without throwing an exception, the calling code has no way of knowing that the transaction is bound to fail. Although you could return a Boolean value or set a Boolean output parameter, you should be consistent and throw an exception to indicate an error condition. This leads to cleaner and more consistent code with a standard approach to error handling.