// PushScope
        //
        // Push a transaction scope onto the stack.
        private void PushScope()
        {
            // Fixup the interop mode before we set current.
            if (!_interopModeSpecified)
            {
                // Transaction.InteropMode will take the interop mode on
                // for the scope in currentScope into account.
                _interopOption = Transaction.InteropMode(_savedCurrentScope);
            }

            // async function yield at await points and main thread can continue execution. We need to make sure the TLS data are restored appropriately.
            SaveTLSContextData();

            if (AsyncFlowEnabled)
            {
                // Async Flow is enabled and CallContext will be used for ambient transaction.
                _threadContextData = CallContextCurrentData.CreateOrGetCurrentData(ContextKey);

                if (_savedCurrentScope == null && _savedCurrent == null)
                {
                    // Clear TLS data so that transaction doesn't leak from current thread.
                    ContextData.TLSCurrentData = null;
                }
            }
            else
            {
                // Legacy TransactionScope. Use TLS to track ambient transaction context.
                _threadContextData = ContextData.TLSCurrentData;
                CallContextCurrentData.ClearCurrentData(ContextKey, false);
            }

            // This call needs to be done first
            SetCurrent(_expectedCurrent);
            _threadContextData.CurrentScope = this;
        }
예제 #2
0
        internal static ContextData LookupContextData(TxLookup defaultLookup)
        {
            if (CallContextCurrentData.TryGetCurrentData(out ContextData currentData))
            {
                if (currentData.CurrentScope == null && currentData.CurrentTransaction == null && defaultLookup != TxLookup.DefaultCallContext)
                {
                    // Clear Call Context Data
                    CallContextCurrentData.ClearCurrentData(null, true);
                    return(TLSCurrentData);
                }

                return(currentData);
            }
            else
            {
                return(TLSCurrentData);
            }
        }
        // PopScope
        //
        // Pop the current transaction scope off the top of the stack
        private void PopScope()
        {
            bool shouldRestoreContextData = true;

            // Clear the current TransactionScope CallContext data
            if (AsyncFlowEnabled)
            {
                CallContextCurrentData.ClearCurrentData(ContextKey, true);
            }

            if (_scopeThread == Thread.CurrentThread)
            {
                // async function yield at await points and main thread can continue execution. We need to make sure the TLS data are restored appropriately.
                // Restore the TLS only if the thread Ids match.
                RestoreSavedTLSContextData();
            }

            // Restore threadContextData to parent CallContext or TLS data
            if (_savedCurrentScope != null)
            {
                if (_savedCurrentScope.AsyncFlowEnabled)
                {
                    _threadContextData = CallContextCurrentData.CreateOrGetCurrentData(_savedCurrentScope.ContextKey);
                }
                else
                {
                    if (_savedCurrentScope._scopeThread != Thread.CurrentThread)
                    {
                        // Clear TLS data so that transaction doesn't leak from current thread.
                        shouldRestoreContextData   = false;
                        ContextData.TLSCurrentData = null;
                    }
                    else
                    {
                        _threadContextData = ContextData.TLSCurrentData;
                    }

                    CallContextCurrentData.ClearCurrentData(_savedCurrentScope.ContextKey, false);
                }
            }
            else
            {
                // No parent TransactionScope present

                // Clear any CallContext data
                CallContextCurrentData.ClearCurrentData(null, false);

                if (_scopeThread != Thread.CurrentThread)
                {
                    // Clear TLS data so that transaction doesn't leak from current thread.
                    shouldRestoreContextData   = false;
                    ContextData.TLSCurrentData = null;
                }
                else
                {
                    // Restore the current data to TLS.
                    ContextData.TLSCurrentData = _threadContextData;
                }
            }

            // prevent restoring the context in an unexpected thread due to thread switch during TransactionScope's Dispose
            if (shouldRestoreContextData)
            {
                _threadContextData.CurrentScope = _savedCurrentScope;
                RestoreCurrent();
            }
        }