Skip to content

Instantly share code, notes, and snippets.

@imranbaloch
Last active October 29, 2015 15:59
Show Gist options
  • Save imranbaloch/27c30178cf4daed1b0b5 to your computer and use it in GitHub Desktop.
Save imranbaloch/27c30178cf4daed1b0b5 to your computer and use it in GitHub Desktop.
//await connection.OpenWithRetryAsync(retryPolicy).ConfigureAwait(false);
//var reader = await command.ExecuteReaderWithRetryAsync(retryPolicy).ConfigureAwait(false);
public static Task OpenWithRetryAsync(this SqlConnection connection,
RetryPolicy retryPolicy)
{
return retryPolicy.ExecuteAsync(connection.OpenAsync);
}
public static class SqlCommandExtensions
{
public static async Task<SqlDataReader> ExecuteReaderWithRetryAsync(this SqlCommand command,
RetryPolicy retryPolicy)
{
return (SqlDataReader) await command.ExecuteWithRetryAsync(retryPolicy, ExecutionType.Reader).ConfigureAwait(false);
}
public static async Task<int> ExecuteNonQueryWithRetryAsync(this SqlCommand command,
RetryPolicy retryPolicy)
{
return (int) await command.ExecuteWithRetryAsync(retryPolicy, ExecutionType.NonQuery).ConfigureAwait(false);
}
public static async Task<object> ExecuteScalarWithRetryAsync(this SqlCommand command,
RetryPolicy retryPolicy)
{
return await command.ExecuteWithRetryAsync(retryPolicy, ExecutionType.Scaler).ConfigureAwait(false);
}
public static async Task<object> ExecuteWithRetryAsync(this SqlCommand command,
RetryPolicy retryPolicy,
ExecutionType executionType)
{
return await retryPolicy.ExecuteAsync(async () =>
{
var hasOpenConnection = await EnsureValidConnectionAsync(command, retryPolicy).ConfigureAwait(false);
try
{
switch (executionType)
{
case ExecutionType.Reader:
return await command.ExecuteReaderAsync().ConfigureAwait(false);
case ExecutionType.NonQuery:
return await command.ExecuteNonQueryAsync().ConfigureAwait(false);
default:
return await command.ExecuteScalarAsync().ConfigureAwait(false);
}
}
catch (Exception exception)
{
if (hasOpenConnection && command.Connection != null && command.Connection.State == ConnectionState.Open)// if we explcitly opened then we have to close it
{
command.Connection.Close();
}
throw;
}
}).ConfigureAwait(false);
}
private static async Task<bool> EnsureValidConnectionAsync(SqlCommand command,
RetryPolicy retryPolicy)
{
if (command.Connection.State != ConnectionState.Open)
{
await command.Connection.OpenWithRetryAsync(retryPolicy);
return true;
}
return false;
}
}
@gmelnik
Copy link

gmelnik commented Jun 3, 2015

Reviewed this with the Topaz's dev lead (@fsimonazzi).

These methods look like async versions of those available at http://topaz.codeplex.com/SourceControl/latest#source/Source/TransientFaultHandling.Data/SqlCommandExtensions.cs. While in this day and age supporting async data access is a requirement, you can see that these extension methods can be implemented on top of the released Topaz binaries anybody can use them (i.e. it doesn't need to be baked into the binaries).

We don't particularly like the approach of funneling all actual execution through a single "implementation" method with a flag indicating the operation (execute reader, execute non query, etc). The original methods avoided that, at the expense of some additional code, but gaining clarity.

Also, this implementation provides a single overload per operation while the underlying methods on SqlCommand provide at least two, if not more, for each operation. In particular, there should be versions getting cancellation tokens.

@imranbaloch
Copy link
Author

Thanks for reviewing and suggesting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment