public static Transaction GetTransactionFromDtcTransaction(
IDtcTransaction transactionNative
)
{
if (!TransactionManager._platformValidated)
{
TransactionManager.ValidatePlatform();
}
bool tooLate = false;
ITransactionShim transactionShim = null;
Guid txIdentifier = Guid.Empty;
OletxTransactionIsolationLevel oletxIsoLevel = OletxTransactionIsolationLevel.ISOLATIONLEVEL_SERIALIZABLE;
OutcomeEnlistment outcomeEnlistment = null;
RealOletxTransaction realTx = null;
OletxTransaction oleTx = null;
if (null == transactionNative)
{
throw new ArgumentNullException("transactionNative");
}
Transaction transaction = null;
if (DiagnosticTrace.Verbose)
{
MethodEnteredTraceRecord.Trace(SR.GetString(SR.TraceSourceOletx),
"TransactionInterop.GetTransactionFromDtc"
);
}
// Let's get the guid of the transaction from the proxy to see if we already
// have an object.
ITransactionNativeInternal myTransactionNative = transactionNative as ITransactionNativeInternal;
if (null == myTransactionNative)
{
throw new ArgumentException(SR.GetString(SR.InvalidArgument), "transactionNative");
}
OletxXactTransInfo xactInfo;
try
{
myTransactionNative.GetTransactionInfo(out xactInfo);
}
catch (COMException ex)
{
if (Oletx.NativeMethods.XACT_E_NOTRANSACTION != ex.ErrorCode)
{
throw;
}
// If we get here, the transaction has appraently already been committed or aborted. Allow creation of the
// OletxTransaction, but it will be marked with a status of InDoubt and attempts to get its Identifier
// property will result in a TransactionException.
tooLate = true;
xactInfo.uow = Guid.Empty;
}
OletxTransactionManager oletxTm = TransactionManager.DistributedTransactionManager;
if (!tooLate)
{
// First check to see if there is a promoted LTM transaction with the same ID. If there
// is, just return that.
transaction = TransactionManager.FindPromotedTransaction(xactInfo.uow);
if (null != transaction)
{
if (DiagnosticTrace.Verbose)
{
MethodExitedTraceRecord.Trace(SR.GetString(SR.TraceSourceOletx),
"TransactionInterop.GetTransactionFromDtcTransaction"
);
}
return(transaction);
}
// We need to create a new RealOletxTransaction...
oletxTm.dtcTransactionManagerLock.AcquireReaderLock(-1);
try
{
outcomeEnlistment = new OutcomeEnlistment();
IntPtr outcomeEnlistmentHandle = IntPtr.Zero;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
outcomeEnlistmentHandle = HandleTable.AllocHandle(outcomeEnlistment);
oletxTm.DtcTransactionManager.ProxyShimFactory.CreateTransactionShim(
transactionNative,
outcomeEnlistmentHandle,
out txIdentifier,
out oletxIsoLevel,
out transactionShim);
}
finally
{
if (transactionShim == null && outcomeEnlistmentHandle != IntPtr.Zero)
{
HandleTable.FreeHandle(outcomeEnlistmentHandle);
}
}
}
catch (COMException comException)
{
OletxTransactionManager.ProxyException(comException);
throw;
}
finally
{
oletxTm.dtcTransactionManagerLock.ReleaseReaderLock();
}
// We need to create a new RealOletxTransaction.
realTx = new RealOletxTransaction(
oletxTm,
transactionShim,
outcomeEnlistment,
txIdentifier,
oletxIsoLevel,
false);
oleTx = new OletxTransaction(realTx);
// If a transaction is found then FindOrCreate will Dispose the oletx
// created.
transaction = TransactionManager.FindOrCreatePromotedTransaction(xactInfo.uow, oleTx);
}
else
{
// It was too late to do a clone of the provided ITransactionNative, so we are just going to
// create a RealOletxTransaction without a transaction shim or outcome enlistment.
realTx = new RealOletxTransaction(
oletxTm,
null,
null,
txIdentifier,
OletxTransactionIsolationLevel.ISOLATIONLEVEL_SERIALIZABLE,
false);
oleTx = new OletxTransaction(realTx);
transaction = new Transaction(oleTx);
TransactionManager.FireDistributedTransactionStarted(transaction);
oleTx.savedLtmPromotedTransaction = transaction;
InternalTransaction.DistributedTransactionOutcome(transaction.internalTransaction, TransactionStatus.InDoubt);
}
if (DiagnosticTrace.Verbose)
{
MethodExitedTraceRecord.Trace(SR.GetString(SR.TraceSourceOletx),
"TransactionInterop.GetTransactionFromDtc"
);
}
return(transaction);
}