Transactions made easy: System.Transactions

Currently in .Net Framework (v1.0 and v1.1) the support for transactions is offered by System.EnterpriseServices and by the System.Data.IDbTransaction, implemented by one of your favorite data provider (see https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconprocessingtransactions.asp?frame=true for more details). Both models have some disadvantages (the first is forcing the inheritance from ServicedComponent and the later offers support only for "local" transactions in that specific database) and together they don't provide a consistent and complete programming model. If all you need is to use a distributed transaction for protection when interacting with two or more resource managers, the only way to do it today is by taking a cumbersome road of using P/Invoke and COM Interop to access the "old and dusted" MSDTC APIs.

With the first beta preview of the next version of .Net Framework, codename Whidbey (available for download at https://lab.msdn.microsoft.com/vs2005/get/default.aspx ), the pain is over and transactions are here with a bright new and simple programming model, offering an exploding number of possibilities which can make your life simpler, safer and even faster. Please welcome System.Transactions [https://lab.msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/N_System_Transactions.asp?frame=true]

The quick summary of the most important features offered by System.Transactions is: an easy to use programming model, support for transactional code blocks using TransactionScope, the concept of the "ambient" transaction using Transaction.Current, a super fast "lightweight" transaction manager for in appdomain transactions that involve at most a single durable resource manager, automatic promotion from "lightweight" to distributed transactions on a need basis and protection against early commits in an async environment using IDependentTransaction.

Over the next weeks I will go over each of these features, with code samples but for today, let me begin by telling you that all you need to get started is to understand the use of TransactionScope. Here is a small piece of code annotated with my explanations:

 using System;
using System.Transactions;

namespace TxScopeSample
{
    class Program
    {
        static void Main(string[] args)
        {
         // create a new transaction scope and protect it 
         // inside an using statement against unexpected exceptions
         using (TransactionScope ts = new TransactionScope())
         {
            // do the transactional work
            // an "ambient" transaction is placed in the current call context
 
            // USER CODE: open connection to database 1
            // the data provider will detect the ambient transaction and automatically enlist into it
            // USER CODE: execute update in database 1 (for instance a credit operation)
 
            // USER CODE: open connection to database 2
            // the data provider will detect the ambient transaction and automatically enlist into it
            // USER CODE: execute update in database 2 (for instance a debit operation)

            // the following code will be executed only if no exception
            // occured in the above code; since we got here ok, let's vote for commit;
            // in most if not all of the cases, this last line will be the same as below
            ts.Complete(); // was ts.Consistent = true; in beta 2
         }

         // when "using" will be  calling Dispose on the transaction scope at the end
         // of the "using" code block, the "ambient" transaction will be commited only and only if
         // the Complete method was called
      }
   }
}

The only code you need to fill in to get your scenarios running is for the lines marked with "USER CODE". And that is all!

When you get the chance to try System.Transactions, please use this blog entry to send me and my team your comments about it. Tell us what you like and what you don't like about this new programming model, we will certainly listen to your feedback. Thanks!

[UPDATE] In Beta 2, the Consistent flag was replaced with a Complete method. Calling TransactionScope.Complete() is equivalent with the statement "TransactionScope.Consistent = true;".