/// <summary>
        /// Determines the throttling conditions from the specified reason code.
        /// </summary>
        /// <param name="reasonCode">The reason code returned by SQL Azure which contains the throttling
        /// mode and the exceeded resource types.</param>
        /// <returns>An instance of the object holding the decoded reason codes returned from SQL Azure when
        /// encountering throttling conditions.</returns>
        public static ThrottlingCondition FromReasonCode(int reasonCode)
        {
            if (reasonCode > 0)
            {
                // Decode throttling mode from the last 2 bits.
                var throttlingMode = (ThrottlingMode)(reasonCode & 3);

                var condition = new ThrottlingCondition {
                    ThrottlingMode = throttlingMode
                };

                // Shift 8 bits to truncate throttling mode.
                var groupCode = reasonCode >> 8;

                // Determine throttling type for all well-known resources that may be subject to throttling
                // conditions.
                condition._throttledResources.Add(Tuple.Create(
                                                      ThrottledResourceType.PhysicalDatabaseSpace,
                                                      (ThrottlingType)(groupCode & 3)));
                condition._throttledResources.Add(Tuple.Create(
                                                      ThrottledResourceType.PhysicalLogSpace,
                                                      (ThrottlingType)((groupCode = groupCode >> 2) & 3)));
                condition._throttledResources.Add(Tuple.Create(
                                                      ThrottledResourceType.LogWriteIoDelay,
                                                      (ThrottlingType)((groupCode = groupCode >> 2) & 3)));
                condition._throttledResources.Add(Tuple.Create(
                                                      ThrottledResourceType.DataReadIoDelay,
                                                      (ThrottlingType)((groupCode = groupCode >> 2) & 3)));
                condition._throttledResources.Add(Tuple.Create(
                                                      ThrottledResourceType.Cpu,
                                                      (ThrottlingType)((groupCode = groupCode >> 2) & 3)));
                condition._throttledResources.Add(Tuple.Create(
                                                      ThrottledResourceType.DatabaseSize,
                                                      (ThrottlingType)((groupCode = groupCode >> 2) & 3)));
                condition._throttledResources.Add(Tuple.Create(
                                                      ThrottledResourceType.Internal,
                                                      (ThrottlingType)((groupCode = groupCode >> 2) & 3)));
                condition._throttledResources.Add(Tuple.Create(
                                                      ThrottledResourceType.WorkerThreads,
                                                      (ThrottlingType)((groupCode = groupCode >> 2) & 3)));
                condition._throttledResources.Add(Tuple.Create(
                                                      ThrottledResourceType.Internal,
                                                      (ThrottlingType)((groupCode >> 2) & 3)));

                return(condition);
            }

            return(Unknown);
        }
        /// <summary>
        /// Determines whether the specified exception represents a transient failure that can be compensated
        /// by a retry.
        /// </summary>
        /// <param name="ex">The exception object to be verified.</param>
        /// <returns>True if the specified exception is considered as transient; otherwise false.</returns>
        public bool IsTransient(Exception ex)
        {
            if (ex != null)
            {
                SqlException sqlException;

                if ((sqlException = ex as SqlException) != null)
                {
                    // Enumerate through all errors found in the exception.
                    foreach (SqlError err in sqlException.Errors)
                    {
                        switch (err.Number)
                        {
                        case ThrottlingCondition.ThrottlingErrorNumber:
                            // SQL Error Code: 40501
                            // The service is currently busy. Retry the request after 10 seconds. Code:
                            // (reason code to be decoded). Decode the reason code from the error
                            // message to determine the grounds for throttling.
                            var condition = ThrottlingCondition.FromError(err);

                            // Attach the decoded values as additional attributes to the original SQL
                            // exception.
                            sqlException.Data[condition.ThrottlingMode.GetType().Name] =
                                condition.ThrottlingMode.ToString();
                            sqlException.Data[condition.GetType().Name] = condition;

                            return(true);

                        case 40197:
                        // SQL Error Code: 40197
                        // The service has encountered an error processing your request. Please try
                        // again.
                        case 10053:
                        // SQL Error Code: 10053
                        // A transport-level error has occurred when receiving results from the
                        // server. An established connection was aborted by the software in your
                        // host machine.
                        case 10054:
                        // SQL Error Code: 10054
                        // A transport-level error has occurred when sending the request to the
                        // server. (provider: TCP Provider, error: 0 - An existing connection was
                        // forcibly closed by the remote host.)
                        case 10060:
                        // SQL Error Code: 10060
                        // A network-related or instance-specific error occurred while establishing
                        // a connection to SQL Server. The server was not found or was not
                        // accessible. Verify that the instance name is correct and that SQL Server
                        // is configured to allow remote connections. (provider: TCP Provider,
                        // error: 0 - A connection attempt failed because the connected party did not
                        // properly respond after a period of time, or established connection failed
                        // because connected host has failed to respond.)"}
                        case 40613:
                        // SQL Error Code: 40613
                        // Database XXXX on server YYYY is not currently available. Please retry the
                        // connection later. If the problem persists, contact customer support, and
                        // provide them the session tracing ID of ZZZZZ.
                        case 40143:
                        // SQL Error Code: 40143
                        // The service has encountered an error processing your request. Please try
                        // again.
                        case 233:
                        // SQL Error Code: 233
                        // The client was unable to establish a connection because of an error during
                        // connection initialization process before login. Possible causes include
                        // the following: the client tried to connect to an unsupported version of
                        // SQL Server; the server was too busy to accept new connections; or there
                        // was a resource limitation (insufficient memory or maximum allowed
                        // connections) on the server. (provider: TCP Provider, error: 0 - An
                        // existing connection was forcibly closed by the remote host.)
                        case 64:
                        // SQL Error Code: 64
                        // A connection was successfully established with the server, but then an
                        // error occurred during the login process. (provider: TCP Provider, error:
                        // 0 - The specified network name is no longer available.)
                        case (int)ProcessNetLibErrorCode.EncryptionNotSupported:
                            // DBNETLIB Error Code: 20
                            // The instance of SQL Server you attempted to connect to does not support
                            // encryption.
                            return(true);
                        }
                    }
                }
                else if (ex is TimeoutException)
                {
                    return(true);
                }
                else
                {
                    EntityException entityException;

                    if ((entityException = ex as EntityException) != null)
                    {
                        return(this.IsTransient(entityException.InnerException));
                    }
                }
            }

            return(false);
        }