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 http://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 http://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 [http://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;”.

Comments (36)

  1. Very nice, I’ve been waiting for it for a long time! Good job!

  2. Kyle Tinsley says:

    This is awesome. Is TransactionScope also the way to handle single database (multi-table) transactions?

  3. Krishna says:

    I tried out the code, the connection was against single SQL Server database but different tables, in code flow below, after Child Class 2 has set the TransactionConsistent option to false and calls a method in Child Class 3, if I put the code within a Transaction Scope, I get "Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction." if I don’t put it in a Transaction Scope, I get "The transaction has already been implicitly or explicitly committed or aborted" If I set the TransactionConsitent bit to true, everything works fine..So how to handle these set of cases? I can send in the actual code in case you need them..

    //Code flow

    //Class 1

    Using (TransactionScope1)

    {

    //Open Connection 1

    //Create Child Class 1

    }

    //Child Class 1

    Using (TransactionScope2)

    {

    //Open Connection 2

    //User Code

    //Set Transaction Consistent to false

    //Create Child Class 2

    }

    //Child Class 2

    {

    //No Transaction Scope, just a read operation

    //Open Connection <- Exception Thrown as "The transaction has already been implicitly or explicitly committed or aborted"

    }

  4. Krishna says:

    What about [Autocommit] and [TransactionOption] attributes similar to that of the support we have in EnterpriseServices. I remember seeing similar attributes in a presentation from the PDC on Distributed Transactions using the Light weight Transaction Manager.

    We are currently using Remoting interception (derived from ContextBound and applied ContextAttributes) for Distributed Transactions without using EnterpriseServices. Since these classes are not documented and might become internal in future releases of the framework we want to move away from this model and use the System.Transaction classes instead, so we were comparing the options available and wanted to know if similar attributes would be made available in the future…basically we are looking for applying the "using TransctionScope" block through attributes and avoid having to write the plumbing code…

    Thanks !

  5. Stuart says:

    Simple transaction need that I can’t figure out how to do it in 1.x *or* with new model:

    I want transparent transactedness for all my ASP.NET pages. By which I mean, each page request should take place in its own transaction; if page load runs to completion with no exception (or terminates with the implicit ThreadAbortException thrown by Response.End, which is usually success in practice) the transaction is committed; otherwise (any other exception) it’s rolled back. I’d also like to be able to access the transaction for rollback by hand, if there’s an error condition that I want to handle some other way than by letting the exception propagate out.

    I thought I could do that with a <%@ Page Transaction=something %> directive, but none of the available values of the Transaction attribute are, well, comprehensible to me at all. I tried a couple of the most likely-sounding candidates and ended up with the site completely screwed, giving an error even after I removed the transaction directive. I didn’t try again after that; there are other developers working on the site too.

    Even with the new transaction stuff described in your blog, I still can’t figure out how I would implement this behavior. I can’t use ‘using’ because there’s nowhere to place the ‘using’ block such that its scope covers all of the page lifecycle. I’m sure I’m missing something obvious – like some documentation that makes sense? 😉

  6. TO: Kyle Tinsley

    Yes, TransactionScope is also good for single-database transactions. In fact, when only one resource manager is used and this resource manager supports promotable transactions, there will be no overhead.

  7. To: Krishna

    I have to see the code to give you an answer. You can send it to me by using the http://blogs.msdn.com/florinlazar/contact.aspx

    One thing that you need to be careful is that it is not recommended to execute any code after you set the consistent flag inside a transaction scope. And in general, if you do set it to false, that means you are in a bad state and you want to abort everything as soon as possible, i.e. don’t do any further work as part of that transaction because you know it will abort.

  8. To: Krishna 2nd comment

    Currently there are no attributes for transactions as part of System.Transactions namespace. They are provided either by EnterpriseServices or will be by "Indigo" (these are the attributes you’ve seen at PDC). Or you can write your own attributes. Please, make sure to read my disclaimer.

  9. To: Stuart

    Did you look at ContextUtil.SetAbort()? I believe this is what you are looking for.

    See more info at http://samples.gotdotnet.com/quickstart/aspplus/doc/mtstransactions.aspx

  10. Krishna says:

    Thanks Florin, I have submitted the code in the link provided..the subject is "System.Transactions Sample Code that throws Exception..See note on Blog" let me know if you need more information..

    how to check the consistency of the transaction?..say a child class has set the transaction scope consistent flag to false..is it possible to check this in the parent class after the call to the child??..

    on the note on Attributes..is there special attribute that we need to inherit from to make the transaction scopes transparent on a method or a class??

    Thanks

  11. xdev says:

    Ping Back来自:blog.csdn.net

  12. Mike says:

    Hey All,

    Using Beta 2 of VS2005 and I’m attempting to use transaction scope in the business layer with no success. Seems to work ok on XP but when we run in a Windows 2003 environment, it fails with access denied.

    Any ideas?

    Mike

  13. florinlazar says:

    To Mike: It’s unusual to get an access denied. I don’t know of any case when System.Transactions or DTC return "Access Denied". You should post more details about your scenario.

  14. hbzhang says:

    When two connections opened in the same transactionscope, it triggers a DTC transaction, not a local transaction, even if two connections point to the same database. I use win2003 and sql2005 with .net 2.0 beta 2.

    Is this behaviour as designed?

    Thanks

  15. Jesús says:

    I have the same trouble than Mike (see post on Thursday, September 15, 2005 11:24 AM) with the System.Transacions.

    We are migrating code from Windows XP and VS2005 beta 2 to Windows Server 2003 and the VS2005 november release. We have the SQL Server in a different server and we are getting the exception message "The transaction has already been implicitly or explicitly committed or aborted".

    The code is like this:

    using (TransactionScope ts = new TransactionScope())

    {

    TableAdapter1 ta1 = new TableAdapter1();

    TableAdapter2 ta2 = new TableAdapter2();

    try

    {

    ta1.Update(dataset);

    ta2.Update(dataset);

    ts.Complete();

    dataset.AcceptChanges();

    return true;

    }

    catch

    {

    dataset.RejectChanges();

    }

    finally

    {

    ts.Dispose();

    }

    }

    Thanks

  16. bogosian says:

    for the TransactionScope – already committed/aborted one can read this very

    useful article:

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=124293&SiteId=1

    bye, good luck

  17. florinlazar says:

    To: hbzhang

    The behavior is currently by design. The WebData/ADO team may be able to optimize this in the future if we (me and you) ask them nicely :)

  18. florinlazar says:

    To: Jesús

    Shouldn’t you put ts.Complete() after dataset.AcceptChanges? I’m not sure what AcceptChanges does, but if is trying to use the current transaction, that might explain why you are getting the exception.

  19. Ashish says:

    To : Jesus,

    Why are u doing ts.Dispose? You are already using “using”.

  20. BKimball says:

    What version of Visual Studio 2005 is needed for the transactional support, or am I just really lost here?

    I put in using System.Transactions; (Well tried to, doesn’t show up in intellisense) but am unable to access anything in the namespace.

    Was this dropped from the final release of VS2K5 or do I need something better than Standard Edition?

  21. Sundar Paranthaman says:

    I am using TransactionScope object to achieve transaction support across 2 components that could have database interactions. Both components make connections to the database and change data. Even though both components connect to the same database with the same connection string, when the second connection is made the transaction escalates to a Distributed Transaction. Is it possible to change this behavior so that the transaction doesn’t escalate since the connections are to the same database with the same connection string. The main reason I want to prevent transaction escalation is our product has to work in WindowsXPSP2 and DTC service is disabled by default.

  22. David says:

    I am geting Transaction aborted Execption, i am using sql Server 2000.

    using (TransactionScope scope = new TransactionScope()
    {
    Store_to_database(int vl,int v2)
    scope.Complete();
    }

    In the Store_to_database function
    i am opening a connection to database, inserting the record. but i m geting Execption
    “The Transaction has Aborted” on connection.open() statement.
    please Help me…..

  23. florinlazar says:

    To: Sundar Paranthaman

    I recommend looking at the ConnectionScope class from

    http://blogs.msdn.com/dataaccess/archive/2006/02/14/532026.aspx

  24. Dan says:

    To use TransactionScope what needs to be installed and running on Windows 2000 or Windows 2003 server & SQL 2000?

    Thanks.

  25. florinlazar says:

    To: Dan

    You need to install .Net Framework 2.0 or higher in order to be able to use System.Transactions.

  26. Khurram says:

    Hi I am having the same error. In our case the application is on win server 2003 and the sql server on win2k. Do we need to install .NET framework 2 on both servers SQL and Web?

  27. Lexapro. Side effects lexapro.

  28. Hair loss propecia drug dht. Propecia. Generic propecia. Propecia generic.