示例#1
0
        override public void Close()
        {
            ConnectionState previousState = State;
            Guid            operationId;
            Guid            clientConnectionId;

            // during the call to Dispose() there is a redundant call to
            // Close(). because of this, the second time Close() is invoked the
            // connection is already in a closed state. this doesn't seem to be a
            // problem except for logging, as we'll get duplicate Before/After/Error
            // log entries
            if (previousState != ConnectionState.Closed)
            {
                operationId = s_diagnosticListener.WriteConnectionCloseBefore(this);
                // we want to cache the ClientConnectionId for After/Error logging, as when the connection
                // is closed then we will lose this identifier
                //
                // note: caching this is only for diagnostics logging purposes
                clientConnectionId = ClientConnectionId;
            }

            SqlStatistics statistics = null;

            Exception e = null;

            try
            {
                statistics = SqlStatistics.StartTimer(Statistics);

                Task reconnectTask = _currentReconnectionTask;
                if (reconnectTask != null && !reconnectTask.IsCompleted)
                {
                    CancellationTokenSource cts = _reconnectionCancellationSource;
                    if (cts != null)
                    {
                        cts.Cancel();
                    }
                    AsyncHelper.WaitForCompletion(reconnectTask, 0, null, rethrowExceptions: false); // we do not need to deal with possible exceptions in reconnection
                    if (State != ConnectionState.Open)
                    {                                                                                // if we cancelled before the connection was opened
                        OnStateChange(DbConnectionInternal.StateChangeClosed);
                    }
                }
                CancelOpenAndWait();
                CloseInnerConnection();
                GC.SuppressFinalize(this);

                if (null != Statistics)
                {
                    ADP.TimerCurrent(out _statistics._closeTimestamp);
                }
            }
            catch (Exception ex)
            {
                e = ex;
                throw;
            }
            finally
            {
                SqlStatistics.StopTimer(statistics);

                // we only want to log this if the previous state of the
                // connection is open, as that's the valid use-case
                if (previousState != ConnectionState.Closed)
                {
                    if (e != null)
                    {
                        s_diagnosticListener.WriteConnectionCloseError(operationId, clientConnectionId, this, e);
                    }
                    else
                    {
                        s_diagnosticListener.WriteConnectionCloseAfter(operationId, clientConnectionId, this);
                    }
                }
            }
        }