Using the TransactionScope class is a terrific way to do implicit transactional programming. It’s incredibly simple, and transactions can span multiple operations across multiple connections.
Basic usage couldn’t be simpler:
using (var ts = new TransactionScope()) { // do transactional stuff ts.Complete(); }
I was working on an application that accepted a batch of items to be processed asynchronously. The desired behavior was to rollback everything if any individual items failed. I figured this would be a snap with TransactionScope. I wrapped the multi-threaded processing code in a TransactionScope, but it didn’t work. The problem is that the TransactionScope does not transcend application and thread boundaries, so the operations launched on a separate thread were executed outside the scope of the ambient transaction.
There is a relatively simple solution to this problem, though. A DependentTransaction can be created from the current transaction and passed into the sub-processes. Here is a simple example:
public void Parent() { using (var ts = new TransactionScope()) { ThreadPool.QueueUserWorkItem( Child, Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete); ts.Complete(); } } public void Child(object o) { var dtx = o as DependentTransaction; using (var ts = new TransactionScope(dtx)) { // do transactional stuff ts.Complete(); } dtx.Complete(); }
i am also looking for same thing but wont able to roll back
using (var _transactionScope = new TransactionScope())
{
try
{
var tt = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
var taskArray =
wbisid.Select(query =>
Task.Factory.StartNew(() => //Task.Factory.StartNew for .NET 4.0
ExecuteQuery(connectionString, query, tt)))
.ToArray();
Task.WaitAll(taskArray);
_transactionScope.Complete();
}
catch (Exception)
{
_transactionScope.Dispose();
//tran.Rollback();
throw;
}
}
public void ExecuteQuery(string connectionString, int w, DependentTransaction t)
{
try
{
using (TransactionScope scope = new TransactionScope(t))
{
DataTable dataTable = null;
if (w == 5)
{
throw new Exception(“F”);
}
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand com = new SqlCommand(“dbo.T1”, connection);
com.ExecuteNonQuery();
connection.Close();
}
scope.Complete();
}
}
catch (Exception)
{
//t.Dispose();
throw;
}
}
how to use transactionscoe using task
What you have looks generally correct to me. The flaw that I see is you’re creating one DependentClone to be passed to all of your tasks. Each separate thread (Task) should have its own clone.
Try changing this:
To this:
thanks but now i am getting another error
at System.Transactions.TransactionStateAborted.CreateAbortingClone(InternalTransaction tx)
at System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, InternalTransaction internalTransaction, Boolean blocking)
at System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption)
at System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent)
at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope.Initialize(Transaction transactionToUse, TimeSpan scopeTimeout, Boolean interopModeSpecified)
at System.Transactions.TransactionScope..ctor(Transaction transactionToUse)
at Scheduler.Form1.ExecuteQuery(String connectionString, Int32 w, DependentTransaction t) in D:\Test Projects\Scheduler\Scheduler\Form1.cs:line 106
Yes, this error makes sense. You cannot create a new dependent clone from a transaction that’s been aborted, and the transaction becomes aborted as soon as one of your queries fails.
You have a choice for how to handle the creation of dependent clones. One option is to create all the clones upfront and then pass one to each new Task. Another is to check the state of the transaction before creating each new clone.
Something like this might work:
I am having Transaction Scope on top of Tasks. Here is my code: I am unable to rollback. Please see you can help. Thanks.
private const string connectionString = @”Data Source=xxxxxx;Initial Catalog=xxxxx;Integrated Security=SSPI”;
static void Main(string[] args)
{
try
{
// This method is a new one uses ‘DependentCloneOption.BlockCommitUntilComplete’, it’s working fine in positive test case
// In negative test case, it fails and aborting the transaction but I am unable to rollback it.
CloneTxnMthod();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine(Environment.NewLine + “End”);
Console.ReadLine();
}
private static void CloneTxnMthod()
{
List tasks = new List();
using (var scope = new TransactionScope())
{
try
{
ThreadPool.QueueUserWorkItem(Child, Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete));
}
catch (AggregateException ae)
{
Transaction.Current.Rollback();
string exceptionMessage = string.Empty;
foreach (var e in ae.Flatten().InnerExceptions)
{
exceptionMessage = $”{exceptionMessage}{Environment.NewLine}{e.Message}”;
}
throw new Exception(exceptionMessage);
}
catch(Exception ex)
{
Transaction.Current.Rollback();
throw new Exception(ex.Message);
}
scope.Complete();
}
}
rivate static void Child(object o)
{
var dtx = o as DependentTransaction;
using (var ts = new TransactionScope(dtx))
{
try
{
CallMethods();
ts.Complete();
dtx.Complete();
}
catch
{
ts.Dispose();
//string exceptionMessage = string.Empty;
//foreach (var e in ae.Flatten().InnerExceptions)
//{
// exceptionMessage = $”{exceptionMessage}{Environment.NewLine}{e.Message}”;
//}
//throw;
}
}
}
private static void CallMethods()
{
try
{
int totalWorkers = 25;
List workers = new List(totalWorkers);
for (int i = 0; i runOne(id));
}
private static void runOne(string id)
{
//try
//{
using (SqlConnection conn1 = new SqlConnection(connectionString))
{
SqlCommand cmd = null;
if (id.Equals(“20”))
{
// This if statement is a negative test case with an invalid table. This ‘TRANSTESTING1’ doesn’t exist
cmd = new SqlCommand(“INSERT INTO TRANSTESTING1 VALUES(” + id + “,’test” + id + “‘)”);
}
else
{
cmd = new SqlCommand(“INSERT INTO TRANSTESTING VALUES(” + id + “,’test” + id + “‘)”);
}
cmd.Connection = conn1;
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
//}
//catch
//{
// throw;
//}
}
Качественный тёплый пол по доступным ценам в Киеве, Одессе, Харькове, Украине