Exception filtering in C# 6.0

Those of you who read my previous post on What's new in C# 6.0 may have noticed that I forget to discuss an important feature of C# 6.0. Well that is exception filtering. I thought about updating the previous post with this feature explained but again felt that it deserves a post of its own. So let's start.

Exception Filtering

Exception filtering is nothing but some condition attached to the catch block. Execution of the catch block depends on this condition. Let me give you a simple example.

In C# 5, we would have done something like the code given below to show users appropriate messages depending on the randomly generated http status codes


using System;
using static System.Console;

namespace NewInCSharp
{
    class Program
    {
        private static void Main(string[] args)
        {
            Random random = new Random();
            var randomExceptions = random.Next(400, 405);
            WriteLine("Generated exception: " + randomExceptions);
            Write("Exception type: ");

            try
            {
                throw new Exception(randomExceptions.ToString());
            }
            catch (Exception ex)
            {
                if(ex.Message.Equals("400"))
                    Write("Bad Request");
                else if (ex.Message.Equals("401"))
                    Write("Unauthorized");
                else if (ex.Message.Equals("402"))
                    Write("Payment Required");
                else if (ex.Message.Equals("403"))
                    Write("Forbidden");
                else if (ex.Message.Equals("404"))
                    Write("Not Found");
            }

            ReadLine();
        }
    }
}

Here I'm randomly generating an exception code randomExceptions. Inside the catch block I'm showing appropriate error message respective to the exception code.

Now you can achieve the same thing using exception filtering but the syntax is bit different. Rather than entering the catch block and check to see which condition met our exception, we can now decide if we even want to enter the specific catch block. Here is the code,


using System;
using static System.Console;

namespace NewInCSharp
{
    class Program
    {
        private static void Main(string[] args)
        {

            Random random = new Random();
            var randomExceptions = random.Next(400, 405);
            WriteLine("Generated exception: " + randomExceptions);
            Write("Exception type: ");

            try
            {
                throw new Exception(randomExceptions.ToString());
            }
            catch (Exception ex) when (ex.Message.Equals("400"))
            {
                Write("Bad Request");
                ReadLine();
            }
            catch (Exception ex) when (ex.Message.Equals("401"))
            {
                Write("Unauthorized");
                ReadLine();
            }
            catch (Exception ex) when (ex.Message.Equals("402"))
            {
                Write("Payment Required");
                ReadLine();
            }
            catch (Exception ex) when (ex.Message.Equals("403"))
            {
                Write("Forbidden");
                ReadLine();
            }
            catch (Exception ex) when (ex.Message.Equals("404"))
            {
                Write("Not Found");
                ReadLine();
            }
        }
    }
}

So, what's the main difference between these two. Well when you enter a catch block, the current execution state is lost. So, the actual cause of the exception is really hard to find. But in the exception filtering we stay where we should be staying i.e. current execution state. This means the stack stays unharmed.

So, exception filtering is good, right? Well there is a catch! Since in the exception filtering, entering a catch block depends on the filter applied on the catch, making a silly mistake can change the whole meaning of the exception. This may actually happen cause the filtering depends on a boolean result and this boolean result can be sent from any code block, making the exception has a different meaning. For example,


using System;
using System.Net.Http;
using System.Threading.Tasks;
using static System.Console;

namespace NewInCSharp
{
    class Program
    {
       private static void Main(string[] args)
        {
            Task.Factory.StartNew(GetWeather);
            ReadLine();
        }

        private static async void GetWeather()
        {
            string customErrorMessage;
            HttpClient client = new HttpClient();

            try
            {
                HttpResponseMessage httpResponseMessage = await client.GetAsync("http://api.openweathemap.org/data/2.5/weather?q=NewYorK");
                WriteLine(httpResponseMessage);
            }
            catch (Exception ex) when (DoASillyMistake(ex.Message, out customErrorMessage))
            {
                WriteLine(customErrorMessage);
            }
        }

        private static bool DoASillyMistake(string exceptionMessage, out string customErrorMessage)
        {
            if (exceptionMessage.Equals("An error occurred while sending the request."))
            {
                customErrorMessage = "Unauthorized.";
                return true;
            }
            else
            {
                customErrorMessage = "Bad Gateway.";
                return true;
            }
        }
    }
}

This is a silly example I must say, but let's assume that if a request to a weather service fails, its because of two reasons, one the service is not up and running [Bad Request] and the second is a user needs to be authorized before accessing the service [Unauthorized]. So, in my code I know for sure that the HttpClient will throw an error message like below if it's a Bad Request.

An error occurred while sending the request.

Again for any other error messages, let's assume it's an Unauthorized request. If you look carefully at the DoASillyMistake(string exceptionMessage, out string customErrorMessage) function, you will see I really did a silly mistake. I've shown the user that they are 'Unauthorized' to access the service while the message should be 'Bad Request' since the service url is not valid [there is a letter missing in the url; 'r' to complete the word weather]. Now the funny and bit irritating part is user will now start looking for a registration process to get access to the service. But sadly we all know that not the case. More funny part is even if he registered himself, from now he will get a 'Bad Request'. So you must be careful when using exception filtering.

But even this side effect can sometimes come in handy. For example, you can attach a filter function which logs error messages and returns false so that the log contains an appropriate exception and also the execution cursor doesn't end up in the catch block. Here is a good example which I found in this open source dotnet git repo documentation, New Language Features in C# 6


private static bool Log(Exception e) { /* log it */ ; return false; }
…
try { … } catch (Exception e) when (Log(e)) {}

So, these are the things you should know while playing with exception filtering. I hope you enjoyed the post. See you later, Alligator! :)