/// <summary> /// Clears the ambient scope from the CallContext and stops tracking its instance. /// Call this when a DbContextScope is being disposed. /// </summary> internal static void RemoveAmbientScope() { #if (NET40 || NETSTANDARD1_0) var current = CallContext.LogicalGetData(AmbientDbContextScopeKey) as InstanceIdentifier; CallContext.LogicalSetData(AmbientDbContextScopeKey, null); #else InstanceIdentifier current = _scopeInstanceIdentifier.Value; _scopeInstanceIdentifier.Value = null; #endif // If there was an ambient scope, we can stop tracking it now if (current != null) { DbContextScopeInstances.Remove(current); } }
/// <summary> /// Get the current ambient scope or null if no ambient scope has been setup. /// </summary> internal static DbContextScope GetAmbientScope() { // Retrieve the identifier of the ambient scope (if any) #if (NET40 || NETSTANDARD1_0) InstanceIdentifier instanceIdentifier = CallContext.LogicalGetData(AmbientDbContextScopeKey) as InstanceIdentifier; #else InstanceIdentifier instanceIdentifier = _scopeInstanceIdentifier.Value; #endif if (instanceIdentifier == null) { return(null); // Either no ambient context has been set or we've crossed an app domain boundary and have (intentionally) lost the ambient context } // Retrieve the DbContextScope instance corresponding to this identifier DbContextScope ambientScope; if (DbContextScopeInstances.TryGetValue(instanceIdentifier, out ambientScope)) { return(ambientScope); } // We have an instance identifier in the CallContext but no corresponding instance // in our DbContextScopeInstances table. This should never happen! The only place where // we remove the instance from the DbContextScopeInstances table is in RemoveAmbientScope(), // which also removes the instance identifier from the CallContext. // // There's only one scenario where this could happen: someone let go of a DbContextScope // instance without disposing it. In that case, the CallContext // would still contain a reference to the scope and we'd still have that scope's instance // in our DbContextScopeInstances table. But since we use a ConditionalWeakTable to store // our DbContextScope instances and are therefore only holding a weak reference to these instances, // the GC would be able to collect it. Once collected by the GC, our ConditionalWeakTable will return // null when queried for that instance. In that case, we're OK. This is a programming error // but our use of a ConditionalWeakTable prevented a leak. System.Diagnostics.Debug.WriteLine("Programming error detected. Found a reference to an ambient DbContextScope in the CallContext but didn't have an instance for it in our DbContextScopeInstances table. This most likely means that this DbContextScope instance wasn't disposed of properly. DbContextScope instance must always be disposed. Review the code for any DbContextScope instance used outside of a 'using' block and fix it so that all DbContextScope instances are disposed of."); return(null); }
protected bool Equals(InstanceIdentifier other) { return(string.Equals(_id, other._id)); }