/// <summary> /// Initializes a new instance of the <see cref="TransactionRetryScope"/> class with the specified retry policy. /// </summary> /// <param name="retryPolicy">The retry policy that determines whether to retry the execution of the entire scope if a transient fault is encountered.</param> /// <param name="unitOfWork">A delegate that represents the executable unit of work that will be retried upon failure.</param> public TransactionRetryScope(RetryPolicy retryPolicy, Action unitOfWork) : this(TransactionScopeOption.Required, retryPolicy, unitOfWork) { }
/// <summary> /// Initializes a new instance of the <see cref="TransactionRetryScope"/> class with the specified time-out value, transaction scope options, and retry policy. /// Uses the ReadCommitted isolation level by default. /// </summary> /// <param name="scopeOption">One of the enumeration values that specifies the transaction requirements associated with this transaction scope.</param> /// <param name="scopeTimeout">The TimeSpan after which the transaction scope times out and aborts the transaction.</param> /// <param name="retryPolicy">The retry policy that determines whether to retry the execution of the entire scope if a transient fault is encountered.</param> /// <param name="unitOfWork">A delegate that represents the executable unit of work that will be retried upon failure.</param> public TransactionRetryScope(TransactionScopeOption scopeOption, TimeSpan scopeTimeout, RetryPolicy retryPolicy, Action unitOfWork) { this.transactionScopeInit = () => { var txOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted, Timeout = scopeTimeout }; return(new TransactionScope(scopeOption, txOptions)); }; this.transactionScope = this.transactionScopeInit(); this.retryPolicy = retryPolicy; this.unitOfWork = unitOfWork; // Set up the callback method for the specified retry policy. this.InitializeRetryPolicy(); }
/// <summary> /// Initializes a new instance of the <see cref="TransactionRetryScope"/> class with the specified requirements and retry policy. /// </summary> /// <param name="scopeOption">One of the enumeration values that specifies the transaction requirements associated with this transaction scope.</param> /// <param name="transactionOptions">A <see cref="System.Transactions.TransactionOptions"/> structure that describes the transaction options to use if a new transaction is created. If an existing transaction is used, the time-out value in this parameter applies to the transaction scope. If that time expires before the scope is disposed, the transaction is aborted.</param> /// <param name="retryPolicy">The retry policy that determines whether to retry the execution of the entire scope if a transient fault is encountered.</param> /// <param name="unitOfWork">A delegate that represents the executable unit of work that will be retried upon failure.</param> public TransactionRetryScope(TransactionScopeOption scopeOption, TransactionOptions transactionOptions, RetryPolicy retryPolicy, Action unitOfWork) { this.transactionScopeInit = () => new TransactionScope(scopeOption, transactionOptions); this.transactionScope = this.transactionScopeInit(); this.retryPolicy = retryPolicy; this.unitOfWork = unitOfWork; // Set up the callback method for the specified retry policy. this.InitializeRetryPolicy(); }
/// <summary> /// Initializes a new instance of the <see cref="TransactionRetryScope"/> class with the specified requirements and retry policy. /// Uses the ReadCommitted isolation level by default. /// </summary> /// <param name="scopeOption">One of the enumeration values that specifies the transaction requirements associated with this transaction scope.</param> /// <param name="retryPolicy">The retry policy that determines whether to retry the execution of the entire scope if a transient fault is encountered.</param> /// <param name="unitOfWork">A delegate that represents the executable unit of work that will be retried upon failure.</param> public TransactionRetryScope(TransactionScopeOption scopeOption, RetryPolicy retryPolicy, Action unitOfWork) : this(scopeOption, TimeSpan.Zero, retryPolicy, unitOfWork) { }
/// <summary> /// Initializes a new instance of the <see cref="ReliableSqlConnection"/> class with the specified connection string /// and a policy that defines whether to retry a request if a connection or command /// fails. /// </summary> /// <param name="connectionString">The connection string used to open the SQL Database.</param> /// <param name="connectionRetryPolicy">The retry policy that defines whether to retry a request if a connection fails to be established.</param> /// <param name="commandRetryPolicy">The retry policy that defines whether to retry a request if a command fails to be executed.</param> public ReliableSqlConnection(string connectionString, RetryPolicy connectionRetryPolicy, RetryPolicy commandRetryPolicy) { this.connectionString = connectionString; this.underlyingConnection = new SqlConnection(connectionString); this.connectionRetryPolicy = connectionRetryPolicy; this.commandRetryPolicy = commandRetryPolicy; // Configure a special retry policy that enables detecting network connectivity errors to be able to determine whether we need to failover // to the original connection string containing the DNS name of the SQL Database server. this.connectionStringFailoverPolicy = new RetryPolicy <NetworkConnectivityErrorDetectionStrategy>(1, TimeSpan.FromMilliseconds(1)); }
/// <summary> /// Initializes a new instance of the <see cref="ReliableSqlConnection"/> class with the specified connection string /// and a policy that defines whether to retry a request if a connection or command /// fails. /// </summary> /// <param name="connectionString">The connection string used to open the SQL Database.</param> /// <param name="retryPolicy">The retry policy that defines whether to retry a request if a connection or command fails.</param> public ReliableSqlConnection(string connectionString, RetryPolicy retryPolicy) : this(connectionString, retryPolicy, RetryManager.Instance.GetDefaultSqlCommandRetryPolicy() ?? retryPolicy) { }
/// <summary> /// Executes a SQL command and returns the number of rows affected. /// </summary> /// <param name="command">The SQL command to be executed.</param> /// <param name="retryPolicy">The retry policy that defines whether to retry a command if a connection fails while executing the command.</param> /// <returns>The number of rows affected.</returns> public int ExecuteCommand(IDbCommand command, RetryPolicy retryPolicy) { var result = this.ExecuteCommand <NonQueryResult>(command, retryPolicy); return(result.RecordsAffected); }
public T ExecuteCommand <T>(IDbCommand command, RetryPolicy retryPolicy, CommandBehavior behavior) { var actionResult = default(T); var resultType = typeof(T); var hasOpenedConnection = false; var closeOpenedConnectionOnSuccess = false; try { (retryPolicy ?? RetryPolicy.NoRetry).ExecuteAction(() => { actionResult = this.connectionStringFailoverPolicy.ExecuteAction(() => { // Make sure the command has been associated with a valid connection. If not, associate it with an opened SQL connection. if (command.Connection == null) { // Open a new connection and assign it to the command object. command.Connection = this.Open(); hasOpenedConnection = true; } // Verify whether or not the connection is valid and is open. This code may be retried therefore // it is important to ensure that a connection is re-established should it have previously failed. if (command.Connection.State != ConnectionState.Open) { command.Connection.Open(); hasOpenedConnection = true; } if (typeof(IDataReader).IsAssignableFrom(resultType)) { closeOpenedConnectionOnSuccess = false; return((T)command.ExecuteReader(behavior)); } if (resultType == typeof(XmlReader)) { if (command is SqlCommand) { object result; var xmlReader = (command as SqlCommand).ExecuteXmlReader(); closeOpenedConnectionOnSuccess = false; if ((behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection) { // Implicit conversion from XmlReader to <T> via an intermediary object. result = new SqlXmlReader(command.Connection, xmlReader); } else { // Implicit conversion from XmlReader to <T> via an intermediary object. result = xmlReader; } return((T)result); } throw new NotSupportedException(); } if (resultType == typeof(NonQueryResult)) { var result = new NonQueryResult { RecordsAffected = command.ExecuteNonQuery() }; closeOpenedConnectionOnSuccess = true; return((T)Convert.ChangeType(result, resultType, CultureInfo.InvariantCulture)); } else { var result = command.ExecuteScalar(); closeOpenedConnectionOnSuccess = true; if (result != null) { return((T)Convert.ChangeType(result, resultType, CultureInfo.InvariantCulture)); } return(default(T)); } }); }); if (hasOpenedConnection && closeOpenedConnectionOnSuccess && command.Connection != null && command.Connection.State == ConnectionState.Open) { command.Connection.Close(); } } catch (Exception) { if (hasOpenedConnection && command.Connection != null && command.Connection.State == ConnectionState.Open) { command.Connection.Close(); } throw; } return(actionResult); }
/// <summary> /// Executes a SQL command by using the specified retry policy, and returns a result that is defined by the specified type <typeparamref name="T"/> /// </summary> /// <typeparam name="T">IDataReader, XmlReader, or any other .NET Framework type that defines the type of result to be returned.</typeparam> /// <param name="command">The SQL command to be executed.</param> /// <param name="retryPolicy">The retry policy that defines whether to retry a command if a connection fails while executing the command.</param> /// <returns>An instance of an IDataReader, XmlReader, or any other .NET Frameork object that contains the result.</returns> public T ExecuteCommand <T>(IDbCommand command, RetryPolicy retryPolicy) { return(this.ExecuteCommand <T>(command, retryPolicy, CommandBehavior.Default)); }