C# – Conditionally catch exceptions with filtering

You can use exception filtering to conditionally catch exceptions, like this:

catch (SqlException ex) when (ex.Number == -2)
Code language: C# (cs)

Note: This feature was added in C# 6.

Any SqlException that doesn’t meet the condition specified in the when clause will not be caught.

Previously, without exception filtering, you’d have to handle that scenario in the catch block and rethrow, like this:

catch (SqlException ex)
{
	if (ex.Number == -2)
	{
		//handle exception properly
	}
	else
	{
		throw;
	}
}
Code language: C# (cs)

Exception filtering example – Conditionally catching transient SqlException

Here’s a full example of using exception filtering to catch transient SQL exceptions. If it’s a transient error, such as a timeout, it retries the query up to three times. Notice that the retry threshold is part of the exception filtering clause. This is because I only want to catch and handle exceptions if I still want to retry the query. You can basically have any conditions you want.

var conString = ConfigurationManager.ConnectionStrings["SQLServer"].ConnectionString;

HashSet<int> transientSqlErrors = new HashSet<int>()
{
	-2, 258
};
int attempts = 1;
int retryThreshold = 3;
TimeSpan commandTimeout = TimeSpan.FromSeconds(1);

using (SqlConnection con = new SqlConnection(conString))
{
	while (true)
	{
		try
		{
			var data = await con.QueryAsync("[spGetTeamsInDivision]",
				new { conference = "NFC", division = "North" },
				commandType: CommandType.StoredProcedure,
				commandTimeout: commandTimeout.Seconds);

			Console.WriteLine(data);
		}
		catch (SqlException ex) 
		when (transientSqlErrors.Contains(ex.Number) && attempts <= retryThreshold)
		{
			Console.WriteLine("Transient SQL error. Increasing timeout and retrying in 5 seconds");
			commandTimeout = TimeSpan.FromSeconds(10);
		}

		await Task.Delay(TimeSpan.FromSeconds(5));
		attempts++;
	}
}
Code language: C# (cs)