Author avatar

Dániel Szabó

Exceptional Exception Filtering

Dániel Szabó

  • Aug 6, 2019
  • 7 Min read
  • 88 Views
  • Aug 6, 2019
  • 7 Min read
  • 88 Views
Languages Frameworks and Tools
C#

Introduction

The exception handling features of C# help you deal with unexpected or exceptional situations that might occur during the execution of your application. There are, basically, three keywords associated with this feature.

Keywords:

  1. try
  2. catch
  3. finally

The try block holds the code for the action you would like to perform, while the catch block holds the code for the actions you would like to perform when an exception occurs. The finally block will be executed whether an exception has occurred or not.

A simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
static double Divide(double a, double b) 
	{
	if (b == 0) 
		{ throw new System.DivideByZeroException(); }
	return a / b;
	}

try 
	{ Console.WriteLine(Divide(10,0)); }
catch
	{ Console.WriteLine("Well this is not what I expected!"); }
finally
	{ Console.WriteLine("I'm gonna be executed anyways!"); }            
csharp

This is the most basic example. We have a Divide function which will raise an exception when the value of the b variable is zero.

The output from the execution is as follows.

1
2
Well, this is not what I expected!
I'm gonna be executed anyways!
bash

You can see how the catch block caught the exception thrown by the function, and the finally block was also executed.

If you don’t specify what exception should be caught by the block, it will catch every exception. You can narrow down the catching to specific exceptions as well.

On top of the exception food-chain lives the Exception class which is the mother of all exceptions.

Custom Exceptions

Suppose that you need to create a specific exception class for your application which reflects the nature of the problem more effectively than what is available, by default, in the C# facilities.

There is a simple way to define your custom exceptions.

1
2
3
4
5
class MyException : Exception
    {
        public MyException() { }
        public MyException(string message) : base(String.Format("Invalid Operation: {0}", message)) { }
    }
csharp

You could customize it with parameters, however, that is outside the scope of this article.

You could simply raise the MyException with, or without, arguments.

1
2
3
throw new MyException("Well this is awkward!");
//or
throw new MyException();
csharp

Exception Filters

Exception filters were introduced to C# when version 6 was released. These clauses determine when a given catch clause should be applied. To put it simply, when the expression in the Expression Filter evaluates to true, the catch clause performs its normal actions on the given exception; otherwise, it is skipped.

There is a wide range of situations when you may want, or need, to apply exception filters. Most of the time, I use them for logging specific exceptions which are relevant for my apps execution. Back in the day, I wrote a small app which verified, for the company where I was working at the time, the redirects of their websites and if they were working properly. It was done by watching out for the 301 code in the HTTP response.

There is an important aspect of filtering, it is the when keyword, which provides you with a logical evaluation of the exception and the condition you are looking for.

Let's look at it this way.

1
2
3
4
5
6
try
	{ ... }
catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("404"))
	{
		return "Site is not available";
	}
csharp

In the try block, let's imagine we have an HTTP client trying to retrieve a website. When the webserver responds to the presence of some errors, like if the site has moved or the content is not available, an exception will be raised. This exception is then caught with the catch block. The when filter ensures that only if the Message contains the 404 string will the block will be executed. So the logic says that if there is an exception then we only care about the exception as long as it contains the appropriate string.

There are pros and cons to this approach. It builds on the assumption that any other exception is irrelevant from the applications execution perspective. It might as well be true, but we need to look at it from a different perspective.

There might be cases when you want these atomic applications to execute a single task. In that instance, any other messages are irrelevant to that application due to the nature of the app.All that matters to the application will be the result that it produces.

There are multiple paradigms that must be taken into consideration when we are using filters, and these decisions will reverberate throughout our entire development process regarding the application.

Coming from our first example, there are ways to catch multiple types of exceptions and filter them.

Let's modify our function by adding another exception.

1
2
3
4
5
static double Divide(double a, double b) {
	if (b == 0) { throw new MyException("Well this is awkward!"); }
	if (b == 10) { throw new MyException("The second value is exactly 10!"); }
		return a / b;
	}
csharp

Now, we’ll handle the exceptions appropriately. When our message contains the awkward, we want to execute the first catch block. When our message holds the exactly, we want to execute the second catch block. We also want to have a unique branch which catches anything else.

1
2
3
4
5
6
7
8
9
10
try
	{ Console.WriteLine(Divide(10, 10));  }
catch (MyException e) when (e.Message.Contains("awkward"))
	{ Console.WriteLine($"Well this is not what I expected: {e.Message}"); }
catch (MyException e) when (e.Message.Contains("exactly"))
	{ Console.WriteLine($"Well something else has happened: {e.Message}"); }
catch (Exception e)
	{ Console.WriteLine($"This was not really handled!"); }
finally
	{ Console.WriteLine("I'm gonna be executed anyways!"); }       
csharp

It is important to note that only the most fitting exception block will be executed if the when keyword's evaluation returns true, it will not go above and beyond just to find an exception to handle it.

Calling the above code returns the following results.

1
2
Well, something else has happened: Invalid Operation: The second value is exactly 10!
I'm gonna be executed anyways!
csharp

As you can see, the second catch block came into play.

Conclusion

Exception filters brought a whole new arsenal of tools with C# version 6. They allow you to fine-tune the flow control of your applications. The handling of exceptions became more robust, while keeping the code as developer-friendly as possible. During our journey, you got to become familiar with the basics of exceptions. You learned to create your own custom exception. Finally, you were introduced to the basics of exception filtering with a nice demo application. I hope this was informative for you. Happy Coding!

0