Building Transacted Code Blocks with System.Transactions.TransactionScope

Transacted code blocks are a group of actions that occur as part of a transaction. With its atomic property, the transaction guarantees that "all or none" of these actions are taking place.

Think of transacted blocks as something similar to:

transacted
{
   ActionA();
   ActionB();
   ActionC();
   ...
}

When you enter the transacted block, the infrastructure creates a transaction and associates it with the current thread context. Each of the actions will notice that a transaction exists and will act accordingly: they will enlist in the transaction and they will perform their associated action similar to a database resource manager i.e. they will do the action in a temporary way, waiting for the commit of the transaction before making the change permanent. When the transacted block finishes and if no exception was encountered in the block until that point, the infrastructure will commit the transaction. Otherwise the transaction is rolled back.

How is this different from the current programming paradigms? Why it is better? Because it simplifies the way we have to deal with errors and exceptions. ActionA, B and C above can be anything from in memory actions like collection additions to registry keys updates, database updates, file system operations. Errors can happen anywhere anytime. In a system where returned error codes are preferred to exceptions you will have to write your code as follows:

{
   bool actionACompleted = false;
   bool actionBCompleted = false;
   bool actionCCompleted = false;

   if( ActionA() )
   {
       actionACompleted = true; 
   }
   else
   {
      goto ERROR;
   }
 
   if( ActionB() )
   {
      actionBCompleted = true; 
   }
   else
   {
      goto ERROR;
   }

   if( ActionC() )
   {
      actionCCompleted = true; 
   }
   else
   {
      goto ERROR;
   }

   return true;

ERROR:
   if( actionCCompleted )
      RollBackC();
   if( actionBCompleted )
      RollBackB();
   if( actionACompleted )
     RollBackA();

   return false;
}

Or if you are using a system that prefers exceptions to error codes:

{
   bool actionACompleted = false;
   bool actionBCompleted = false;
   bool actionCCompleted = false;

   try
   {
      ActionA();
      actionACompleted = true;
      ActionB();
      actionBCompleted = true;
      ActionC();
      actionCCompleted = true;
    }
    catch(...)
    {
       if( actionCCompleted )
          RollBackC();
       if( actionBCompleted )
          RollBackB();
       if( actionACompleted )
          RollBackA();
       throw;  
   }
}

TransactionScope offered by System.Transactions is the first step towards building transacted code blocks. The ideal "transacted" code block translates in .Net Framework 2.0 in:

using( TransactionScope ts = new TransactionScope())
{
   ActionA();
   ActionB();
   ActionC();

   ts.Complete();
}

With the requirement that each action is transaction aware and uses the static Transaction.Current located in the thread context to participate in the transaction.

Comments

  • Anonymous
    April 16, 2005
    Nice. Is it that, like - let's say - a kind of "inner aspect"?
  • Anonymous
    May 11, 2005
    RePost:
    http://www.yeyan.cn/Programming/SystemTransactionsCodeBlocks.aspx
  • Anonymous
    September 09, 2005
    The comment has been removed
  • Anonymous
    October 03, 2005
    To: John

    This usually indicates that your local DTC cannot talk with the DTC on remote machine. What OS are using? Are you in a Windows domain?