I am trying to use System.Transactions (TransactionScope) to coordinate a set of processes, each of which works with some databases. Ultimately, all processes must commit or roll back atomically through one parent process. Unfortunately, nothing I've tried so far is working.
My main strategy is TransactionScope in the parent process, saving it to a file and calling the child process that downloads the file, uses the transaction inside its own TransactionScope and returns to the parent.
But this does not work for me. When I return from calling my first child, I sometimes see that the parent transaction is marked as Aborted. Attempting to clone it then throws a TransactionAbortedException.
I also saw exceptions, when the second child tries to deserialize the transaction, I get a TransactionException with the code 0x8004d00e.
I am trying to do what is described in TransactionScope through AppDomains and processes , and http://blogs.microsoft.co.il/blogs/sasha/archive/2010/04/30/propagating-a-transaction-across-appdomains.aspx . Regardless, no luck.
Here are some things I tried without success:
- Creating a dependent broadcast through DependentClone () in a child process from a loaded transaction
- Creating a dependent broadcast through DependentClone () in the parent process before saving the transaction to a file
- Creating a clone () in the parent process before saving the transaction to a file
- Saving a transaction using serialization
- TransactionInterop.GetTransactionFromTransmitterPropagationToken()
- TransactionScope
- /
- /
- CommittableTransaction
:
System.Transactions.TransactionException: . --- > System.Runtime.InteropServices.COMException: ( HRESULT: 0x8004D00E)
( DependentClone()):
System.Transactions.TransactionAbortedException: . System.Transactions.TransactionStatePromotedAborted.CreateBlockingClone(In
ternalTransaction tx) System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, In
ternalTransaction internalTransaction, Boolean blocking) System.Transactions.Transaction.DependentClone(DependentCloneOption cloneO
ption)
, ? .
( , ):
using (TransactionScope scope = new TransactionScope())
{
DoChildOperation_OutOfProc(1, Transaction.Current);
DoChildOperation_OutOfProc(2, Transaction.Current);
scope.Complete();
}
...
private static void DoChildOperation_OutOfProc(int id, Transaction transaction)
{
string tranFile = string.Format("ChildTran_{0}.txt", id);
SaveTransactionToFile(transaction, tranFile);
Process process = new Process();
process.StartInfo = new ProcessStartInfo(Process.GetCurrentProcess().MainModule.FileName.Replace(".vshost", string.Empty),
string.Format("-CHILDID={0} -TRANFILE={1}", id, tranFile));
process.StartInfo.UseShellExecute = false;
process.Start();
process.WaitForExit();
}
private static void SaveTransactionToFile(Transaction transaction, string tranFile)
{
byte[] transactionBytes =
TransactionInterop.GetTransmitterPropagationToken(transaction);
string tranFileContents = Convert.ToBase64String(transactionBytes);
File.WriteAllText(tranFile, tranFileContents);
}
private static Transaction LoadTransactionFromFile(string tranFile)
{
string tranFileContents = File.ReadAllText(tranFile);
File.Delete(tranFile);
byte[] tranBytes = Convert.FromBase64String(tranFileContents);
Transaction tran =
TransactionInterop.GetTransactionFromTransmitterPropagationToken(tranBytes);
return tran;
}
private static void DoChildOperation(int id, Transaction childTransaction)
{
using (TransactionScope scope = new TransactionScope(childTransaction))
{
scope.Complete();
}