Search code examples
c#wcftransactionscope

TransactionScope and WCF callback


I was going through a piece of code and came across the following:

 using(var transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionScopeOptions { IsolationLevel = IsolationLevel.Snapshot })
    {
        List<Task> tasks = new List<Task>();
        try
        {
            // Perform some database operation to read data (These operations are happening with a transaction scope having scopeoption as "Required" and isolationlevel as "ReadCommitted")
           // Filter the data
           // At this point the code already has a reference to a WCF duplex callback
           // Create a List<Task> and a
           foreach(var data in List<SomeData>)
           {
               var task = Task.Factory.StartNew(() => {
                  **(WCF Duplex Callback Instance).Process(data);**
           });
           tasks.Add(task);
         }
       }
       catch(Exception ex)
       {
         // Log exception details
       }

       transactionScope.Complete();

    }

try
{
   Task.WaitAll(tasks);
}
catch(AggregateException ae)
{
    ae.Handle( ex => {
         // log exception details
         return true;
    });
}

Questions:

  1. The parent transaction isolation level is "Snapshot" while the inner database reads are using "ReadCommitted". What will be the actual transaction isolation level?

  2. Let's say there are two tasks. Task 1 processes just fine and sends to the WCF client on the callback channel. But task 2 raises an exception. I guess at this time all the activities performed within the parent transaction scope should rollback. But I'm not sure what it means to rollback a set of data already sent over the WCF callback channel that has reached the client.


Solution

  • 1) It depends, if you mean nested TransactionScope's then according to MSDN you cannot have them nested with different isolation level:

    When using nested TransactionScope objects, all nested scopes must be configured to use exactly the same isolation level if they want to join the ambient transaction. If a nested TransactionScope object tries to join the ambient transaction yet it specifies a different isolation level, an ArgumentException is thrown

    However if you are using some stored procedures, functions or just running raw SQL you may explicitly change the isolation level and it remains set for that connection until it is explicitly changed again. But please note it will not be propagated back to TransactionScope object.

    2) It means that all changes done via a resource manager will be rollbacked. Of course if you just query a database and transfer the results back over a channel there is nothing to rollback but if you update a database for example the changes should be rollbacked in this case.

    Hope it helps!