System.Transactions.TransactionScope.Dispose C# (CSharp) Method

Dispose() public method

public Dispose ( ) : void
return void
        public void Dispose()
        {
            bool successful = false;

            TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
            if (etwLog.IsEnabled())
            {
                etwLog.MethodEnter(TraceSourceType.TraceSourceBase, this);
            }
            if (_disposed)
            {
                if (etwLog.IsEnabled())
                {
                    etwLog.MethodExit(TraceSourceType.TraceSourceBase, this);
                }
                return;
            }

            // Dispose for a scope can only be called on the thread where the scope was created.
            if ((_scopeThread != Thread.CurrentThread) && !AsyncFlowEnabled)
            {
                if (etwLog.IsEnabled())
                {
                    etwLog.InvalidOperation("TransactionScope", "InvalidScopeThread");
                }

                throw new InvalidOperationException(SR.InvalidScopeThread);
            }

            Exception exToThrow = null;

            try
            {
                // Single threaded from this point
                _disposed = true;

                // First, lets pop the "stack" of TransactionScopes and dispose each one that is above us in
                // the stack, making sure they are NOT consistent before disposing them.

                // Optimize the first lookup by getting both the actual current scope and actual current
                // transaction at the same time.
                TransactionScope actualCurrentScope = _threadContextData.CurrentScope;
                Transaction contextTransaction = null;
                Transaction current = Transaction.FastGetTransaction(actualCurrentScope, _threadContextData, out contextTransaction);

                if (!Equals(actualCurrentScope))
                {
                    // Ok this is bad.  But just how bad is it.  The worst case scenario is that someone is
                    // poping scopes out of order and has placed a new transaction in the top level scope.
                    // Check for that now.
                    if (actualCurrentScope == null)
                    {
                        // Something must have gone wrong trying to clean up a bad scope
                        // stack previously.
                        // Make a best effort to abort the active transaction.
                        Transaction rollbackTransaction = _committableTransaction;
                        if (rollbackTransaction == null)
                        {
                            rollbackTransaction = _dependentTransaction;
                        }
                        Debug.Assert(rollbackTransaction != null);
                        rollbackTransaction.Rollback();

                        successful = true;
                        throw TransactionException.CreateInvalidOperationException(
                            TraceSourceType.TraceSourceBase, SR.TransactionScopeInvalidNesting, null, rollbackTransaction.DistributedTxId);
                    }
                    // Verify that expectedCurrent is the same as the "current" current if we the interopOption value is None.
                    else if (EnterpriseServicesInteropOption.None == actualCurrentScope._interopOption)
                    {
                        if (((null != actualCurrentScope._expectedCurrent) && (!actualCurrentScope._expectedCurrent.Equals(current)))
                            ||
                            ((null != current) && (null == actualCurrentScope._expectedCurrent))
                            )
                        {
                            TransactionTraceIdentifier myId;
                            TransactionTraceIdentifier currentId;

                            if (null == current)
                            {
                                currentId = TransactionTraceIdentifier.Empty;
                            }
                            else
                            {
                                currentId = current.TransactionTraceId;
                            }

                            if (null == _expectedCurrent)
                            {
                                myId = TransactionTraceIdentifier.Empty;
                            }
                            else
                            {
                                myId = _expectedCurrent.TransactionTraceId;
                            }

                            if (etwLog.IsEnabled())
                            {
                                etwLog.TransactionScopeCurrentChanged(currentId, myId);
                            }

                            exToThrow = TransactionException.CreateInvalidOperationException(TraceSourceType.TraceSourceBase, SR.TransactionScopeIncorrectCurrent, null,
                                current == null ? Guid.Empty : current.DistributedTxId);

                            // If there is a current transaction, abort it.
                            if (null != current)
                            {
                                try
                                {
                                    current.Rollback();
                                }
                                catch (TransactionException)
                                {
                                    // we are already going to throw and exception, so just ignore this one.
                                }
                                catch (ObjectDisposedException)
                                {
                                    // Dito
                                }
                            }
                        }
                    }

                    // Now fix up the scopes
                    while (!Equals(actualCurrentScope))
                    {
                        if (null == exToThrow)
                        {
                            exToThrow = TransactionException.CreateInvalidOperationException(TraceSourceType.TraceSourceBase, SR.TransactionScopeInvalidNesting, null,
                                current == null ? Guid.Empty : current.DistributedTxId);
                        }

                        if (null == actualCurrentScope._expectedCurrent)
                        {
                            if (etwLog.IsEnabled())
                            {
                                etwLog.TransactionScopeNestedIncorrectly(TransactionTraceIdentifier.Empty);
                            }
                        }
                        else
                        {
                            if (etwLog.IsEnabled())
                            {
                                etwLog.TransactionScopeNestedIncorrectly(actualCurrentScope._expectedCurrent.TransactionTraceId);
                            }
                        }

                        actualCurrentScope._complete = false;
                        try
                        {
                            actualCurrentScope.InternalDispose();
                        }
                        catch (TransactionException)
                        {
                            // we are already going to throw an exception, so just ignore this one.
                        }

                        actualCurrentScope = _threadContextData.CurrentScope;

                        // We want to fail this scope, too, because work may have been done in one of these other
                        // nested scopes that really should have been done in my scope.
                        _complete = false;
                    }
                }
                else
                {
                    // Verify that expectedCurrent is the same as the "current" current if we the interopOption value is None.
                    // If we got here, actualCurrentScope is the same as "this".
                    if (EnterpriseServicesInteropOption.None == _interopOption)
                    {
                        if (((null != _expectedCurrent) && (!_expectedCurrent.Equals(current)))
                            || ((null != current) && (null == _expectedCurrent))
                            )
                        {
                            TransactionTraceIdentifier myId;
                            TransactionTraceIdentifier currentId;

                            if (null == current)
                            {
                                currentId = TransactionTraceIdentifier.Empty;
                            }
                            else
                            {
                                currentId = current.TransactionTraceId;
                            }

                            if (null == _expectedCurrent)
                            {
                                myId = TransactionTraceIdentifier.Empty;
                            }
                            else
                            {
                                myId = _expectedCurrent.TransactionTraceId;
                            }

                            if (etwLog.IsEnabled())
                            {
                                etwLog.TransactionScopeCurrentChanged(currentId, myId);
                            }

                            if (null == exToThrow)
                            {
                                exToThrow = TransactionException.CreateInvalidOperationException(TraceSourceType.TraceSourceBase, SR.TransactionScopeIncorrectCurrent, null,
                                    current == null ? Guid.Empty : current.DistributedTxId);
                            }

                            // If there is a current transaction, abort it.
                            if (null != current)
                            {
                                try
                                {
                                    current.Rollback();
                                }
                                catch (TransactionException)
                                {
                                    // we are already going to throw and exception, so just ignore this one.
                                }
                                catch (ObjectDisposedException)
                                {
                                    // Dito
                                }
                            }
                            // Set consistent to false so that the subsequent call to
                            // InternalDispose below will rollback this.expectedCurrent.
                            _complete = false;
                        }
                    }
                }
                successful = true;
            }
            finally
            {
                if (!successful)
                {
                    PopScope();
                }
            }

            // No try..catch here.  Just let any exception thrown by InternalDispose go out.
            InternalDispose();

            if (null != exToThrow)
            {
                throw exToThrow;
            }

            if (etwLog.IsEnabled())
            {
                etwLog.MethodExit(TraceSourceType.TraceSourceBase, this);
            }
        }

Usage Example

        static void RetrieveMoney(decimal amount, string cardNumber, string cardPin)
        {
            if (cardNumber == null)
            {
                throw new ArgumentNullException("cardNumber", "Provided card number cannot be null!");
            }

            if (cardPin == null)
            {
                throw new ArgumentNullException("cardPIN", "Provided card PIN cannot be null!");
            }

            if (cardNumber.Length != 10)
            {
                throw new ArgumentException(
                    "Provided card number is invalid! Card number must consist of 10 digits!");
            }

            if (cardPin.Length != 4)
            {
                throw new ArgumentException(
                    "Provided card PIN is invalid! Card PIN must consist of 4 digits!");
            }

            using (var scope = new TransactionScope(TransactionScopeOption.Required,
                new TransactionOptions() { IsolationLevel = IsolationLevel.RepeatableRead }))
            {
                using (var atmContext = new ATMEntities())
                {
                    var cardAccount = atmContext.CardAccounts.FirstOrDefault(
                        ca => ca.CardNumber.CompareTo(cardNumber) == 0 &&
                        ca.CardPIN.CompareTo(cardPin) == 0);

                    if (cardAccount == null)
                    {
                        scope.Dispose();
                        throw new TransactionException(
                            "There is no card account with provided card number and PIN!");
                    }

                    if (cardAccount.CardCash < amount)
                    {
                        scope.Dispose();
                        throw new TransactionException(
                            "There is no enough money in the account to retrive the requested amount!");
                    }

                    cardAccount.CardCash -= amount;
                    atmContext.SaveChanges();
                }

                scope.Complete();
            }
        }
All Usage Examples Of System.Transactions.TransactionScope::Dispose