internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) { Bid.PoolerTrace("<prov.DbConnectionInternal.CloseConnection|RES|CPOOL> %d# Closing.\n", this.ObjectID); if (connectionFactory.SetInnerConnectionFrom(owningObject, DbConnectionOpenBusy.SingletonInstance, this)) { try { DbConnectionPool pool = this.Pool; Transaction enlistedTransaction = this.EnlistedTransaction; if (null != enlistedTransaction) { bool flag = true; try { flag = TransactionStatus.Active != enlistedTransaction.TransactionInformation.Status; } catch (TransactionException) { } if (flag) { this.DetachTransaction(enlistedTransaction, true); } } if (pool != null) { pool.PutObject(this, owningObject); } else { this.Deactivate(); this.PerformanceCounters.HardDisconnectsPerSecond.Increment(); this._owningObject.Target = null; if (this.IsTransactionRoot) { this.SetInStasis(); } else { this.PerformanceCounters.NumberOfNonPooledConnections.Decrement(); if (base.GetType() != typeof(SqlInternalConnectionSmi)) { this.Dispose(); } } } } finally { connectionFactory.SetInnerConnectionEvent(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance); } } }
internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory) { // The implementation here is the implementation required for the // "open" internal connections, since our own private "closed" // singleton internal connection objects override this method to // prevent anything funny from happening (like disposing themselves // or putting them into a connection pool) // // Derived class should override DbConnectionInternal.Deactivate and DbConnectionInternal.Dispose // for cleaning up after DbConnection.Close // protected override void Deactivate() { // override DbConnectionInternal.Close // // do derived class connection deactivation for both pooled & non-pooled connections // } // public override void Dispose() { // override DbConnectionInternal.Close // // do derived class cleanup // base.Dispose(); // } // // overriding DbConnection.Close is also possible, but must provider for their own synchronization // public override void Close() { // override DbConnection.Close // base.Close(); // // do derived class outer connection for both pooled & non-pooled connections // // user must do their own synchronization here // } // // if the DbConnectionInternal derived class needs to close the connection it should // delegate to the DbConnection if one exists or directly call dispose // DbConnection owningObject = (DbConnection)Owner; // if (null != owningObject) { // owningObject.Close(); // force the closed state on the outer object. // } // else { // Dispose(); // } // //////////////////////////////////////////////////////////////// // DON'T MESS WITH THIS CODE UNLESS YOU KNOW WHAT YOU'RE DOING! //////////////////////////////////////////////////////////////// Debug.Assert(null != owningObject, "null owningObject"); Debug.Assert(null != connectionFactory, "null connectionFactory"); // if an exception occurs after the state change but before the try block // the connection will be stuck in OpenBusy state. The commented out try-catch // block doesn't really help because a ThreadAbort during the finally block // would just revert the connection to a bad state. // Open->Closed: guarantee internal connection is returned to correct pool if (connectionFactory.SetInnerConnectionFrom(owningObject, DbConnectionOpenBusy.SingletonInstance, this)) { // Lock to prevent race condition with cancellation lock (this) { object lockToken = ObtainAdditionalLocksForClose(); try { PrepareForCloseConnection(); DbConnectionPool connectionPool = Pool; // Detach from enlisted transactions that are no longer active on close DetachCurrentTransactionIfEnded(); // The singleton closed classes won't have owners and // connection pools, and we won't want to put them back // into the pool. if (null != connectionPool) { connectionPool.PutObject(this, owningObject); // PutObject calls Deactivate for us... // NOTE: Before we leave the PutObject call, another // thread may have already popped the connection from // the pool, so don't expect to be able to verify it. } else { Deactivate(); // ensure we de-activate non-pooled connections, or the data readers and transactions may not get cleaned up... // To prevent an endless recursion, we need to clear // the owning object before we call dispose so that // we can't get here a second time... Ordinarily, I // would call setting the owner to null a hack, but // this is safe since we're about to dispose the // object and it won't have an owner after that for // certain. _owningObject.Target = null; if (IsTransactionRoot) { SetInStasis(); } else { Dispose(); } } } finally { ReleaseAdditionalLocksForClose(lockToken); // if a ThreadAbort puts us here then its possible the outer connection will not reference // this and this will be orphaned, not reclaimed by object pool until outer connection goes out of scope. connectionFactory.SetInnerConnectionEvent(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance); } } } }