Example #1
0
        public AmbientContextSuppressor()
        {
            _savedScope = AmbientContextScopeMagic.GetAmbientScope();

            // We're hiding the ambient scope but not removing its instance
            // altogether. This is to be tolerant to some programming errors.
            //
            // Suppose we removed the ambient scope instance here. If someone
            // was to start a parallel task without suppressing
            // the ambient context and then tried to suppress the ambient
            // context within the parallel task while the original flow
            // of execution was still ongoing (a strange thing to do, I know,
            // but I'm sure this is going to happen), we would end up
            // removing the ambient context instance of the original flow
            // of execution from within the parallel flow of execution!
            //
            // As a result, any code in the original flow of execution
            // that would attempt to access the ambient scope would end up
            // with a null value since we removed the instance.
            //
            // It would be a fairly nasty bug to track down. So don't let
            // that happen. Hiding the ambient scope (i.e. clearing the CallContext
            // in our execution flow but leaving the ambient scope instance untouched)
            // is safe.
            AmbientContextScopeMagic.HideAmbientScope();
        }
Example #2
0
        public DbContextCollection(DbContextScopeBase dbContextScope, IAmbientDbContextFactory ambientDbContextFactory, ILoggerFactory loggerFactory, bool readOnly, IsolationLevel?isolationLevel)
        {
            _disposed  = false;
            _completed = false;
            _logger    = loggerFactory.Create <DbContextCollection>();

            InitializedDbContexts = new Dictionary <Type, (DbContext DbContext, IDbContextProxyBypass Proxy)>();
            _transactions         = new Dictionary <DbContext, IDbContextTransaction>();

            _dbContextScope          = dbContextScope;
            _readOnly                = readOnly;
            _isolationLevel          = isolationLevel;
            _ambientDbContextFactory = ambientDbContextFactory;
        }
Example #3
0
        public void Dispose()
        {
            if (_disposed)
            {
                return;
            }

            if (_savedScope != null)
            {
                AmbientContextScopeMagic.SetAmbientScope(_savedScope);
                _savedScope = null;
            }

            _disposed = true;
        }
Example #4
0
        /// <summary>
        /// Makes the provided 'dbContextScope' available as the the ambient scope via the CallContext.
        /// </summary>
        internal static void SetAmbientScope(DbContextScopeBase newAmbientScope)
        {
            if (newAmbientScope == null)
            {
                throw new ArgumentNullException(nameof(newAmbientScope));
            }

            //return Thread.CurrentThread.GetExecutionContextReader().LogicalCallContext.GetData(name);
            var current = CallContext.GetData <InstanceIdentifier>(ambientDbContextScopeKey);

            if (current == newAmbientScope.InstanceIdentifier)
            {
                return;
            }

            // Store the new scope's instance identifier in the CallContext, making it the ambient scope
            CallContext.SetData(ambientDbContextScopeKey, newAmbientScope.InstanceIdentifier);

            // Keep track of this instance (or do nothing if we're already tracking it)
            dbContextScopeInstances.GetValue(newAmbientScope.InstanceIdentifier, key => newAmbientScope);
        }
Example #5
0
        protected DbContextScopeBase(DbContextScopeOption joiningOption, bool readOnly, IsolationLevel?isolationLevel, IAmbientDbContextFactory ambientDbContextFactory, ILoggerFactory loggerFactory, IScopeDiagnostic scopeDiagnostic)
        {
            if (isolationLevel.HasValue && joiningOption == DbContextScopeOption.JoinExisting)
            {
                throw new ArgumentException("Cannot join an ambient DbContextScope when an explicit database transaction "
                                            + "is required. When requiring explicit database transactions to be used (i.e. when the "
                                            + "'isolationLevel' parameter is set), you must not also ask to join the ambient context "
                                            + "(i.e. the 'joinAmbient' parameter must be set to false).");
            }

            _scopeDiagnostic = scopeDiagnostic;
            _logger          = loggerFactory.Create <DbContextScopeBase>();

            _readonly = readOnly;

            _disposed  = false;
            _completed = false;

            _parentScope = AmbientContextScopeMagic.GetAmbientScope();
            if (_parentScope != null && joiningOption == DbContextScopeOption.JoinExisting)
            {
                if (_parentScope._readonly && !_readonly)
                {
                    throw new InvalidOperationException("Cannot nest a read/write DbContextScope within a read-only DbContextScope.");
                }

                _nested     = true;
                _dbContexts = _parentScope._dbContexts;
            }
            else
            {
                _nested     = false;
                _dbContexts = new DbContextCollection(this, ambientDbContextFactory, loggerFactory, readOnly, isolationLevel);
            }

            SetScope();
        }