C# – Exception filters – conditionally catch exceptions

In C# 6 they added exception filtering. This allows you to conditionally catch exceptions.

To filter exceptions, you use the when clause after the catch clause, like this:

catch (SqlException ex) when (ex.Number == -2)

Any SqlException that doesn’t meet the condition 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;
	}
}

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.

static async Task Main(string[] args)
{
	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++;
		}
	}

}

Leave a Comment