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(); }
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; }
public void Dispose() { if (_disposed) { return; } if (_savedScope != null) { AmbientContextScopeMagic.SetAmbientScope(_savedScope); _savedScope = null; } _disposed = true; }
/// <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); }
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(); }