Beispiel #1
0
        public DbContextScope(DbContextScopeOption joiningOption, bool readOnly, IsolationLevel?isolationLevel, IDbContextFactory dbContextFactory = null)
        {
            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).");
            }

            _disposed    = false;
            _completed   = false;
            _readOnly    = readOnly;
            _parentScope = AmbientScope.GetAmbientScope();
            if (_parentScope != null && joiningOption == DbContextScopeOption.JoinExisting)
            {
                if (_parentScope._readOnly && !this._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(readOnly, isolationLevel, dbContextFactory);
            }

            AmbientScope.SetAmbientScope(this);
        }
Beispiel #2
0
        public AmbientContextSuppressor()
        {
            _savedScope = AmbientScope.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.
            AmbientScope.HideAmbientScope();
        }
Beispiel #3
0
        public void Dispose()
        {
            if (_disposed)
            {
                return;
            }

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

            _disposed = true;
        }
Beispiel #4
0
        public void Dispose()
        {
            if (_disposed)
            {
                return;
            }

            if (!_nested)
            {
                if (!_completed)
                {
                    try
                    {
                        if (_readOnly)
                        {
                            CommitInternals();
                        }
                        else
                        {
                            RollbackInternal();
                        }
                    }
                    catch (Exception e)
                    {
                        System.Diagnostics.Debug.WriteLine(e);
                    }

                    _completed = true;
                }

                _dbContexts.Dispose();
            }

            // Pop ourself from the ambient scope stack
            var currentAmbientScope = AmbientScope.GetAmbientScope();

            if (currentAmbientScope != this) // This is a serious programming error. Worth throwing here.
            {
                throw new InvalidOperationException("DbContextScope instances must be disposed of in the order in which they were created!");
            }

            AmbientScope.RemoveAmbientScope();

            if (_parentScope != null)
            {
                if (_parentScope._disposed)
                {
                    var message = @"PROGRAMMING ERROR - When attempting to dispose a DbContextScope, we found that our parent DbContextScope has already been disposed! This means that someone started a parallel flow of execution (e.g. created a TPL task, created a thread or enqueued a work item on the ThreadPool) within the context of a DbContextScope without suppressing the ambient context first. 

In order to fix this:
1) Look at the stack trace below - this is the stack trace of the parallel task in question.
2) Find out where this parallel task was created.
3) Change the code so that the ambient context is suppressed before the parallel task is created. You can do this with IDbContextScopeFactory.SuppressAmbientContext() (wrap the parallel task creation code block in this). 

Stack Trace:
" + Environment.StackTrace;

                    System.Diagnostics.Debug.WriteLine(message);
                }
                else
                {
                    AmbientScope.SetAmbientScope(_parentScope);
                }
            }

            _disposed = true;
        }
        public TDbContext Get <TDbContext>() where TDbContext : DbContext
        {
            var ambientDbContextScope = AmbientScope.GetAmbientScope();

            return(ambientDbContextScope == null ? null : ambientDbContextScope.DbContexts.Get <TDbContext>());
        }