Using Exception Filters In C#

by Kenji Elzerman
Using Exception Filters In C# - Kens Learning Curvea

We all know exceptions. Sometimes we love them, but most of the time we hate them. Especially when the application throws an exception when we least expect it. Of course, we can use a try-catch to catch the exception, write code to handle the problem accordingly and move on. But just a simple try-catch doesn’t always do the job. Exception filters in C# help us filter the same exception types to act more accurately.

Goals

This article is not about exceptions in general, there are other articles on this. This one is purely written for exception filters. After this article you

  • Know what an exception filter is.
  • Can implement and use exception filters.

The Boring Theory

Let’s start with some theory on what an exception filter is. We all know what an exception is and we all know what a filter is. Alright, now combine these two: Exception filters!

As of C# 6, we can use filters on our exceptions, making the list of catches easier to read. Using the when statement behind the catch makes catching the exceptions based on conditions.

Let’s look at this a little more. Some methods can throw multiple exceptions, which isn’t strange. In some cases, a method can throw multiple exceptions of the same type, like Exception or ArgumentNullException. Catching and handling exceptions of the same type from the same method can be a bit hard.

Imagine you have a method that throws an ArgumentException 3 times for different arguments (parameters):

  • The ID cannot be 0 or less
  • The name of the user is too short
  • Can’t find a department on the new user

And, for the sake of argument, let’s make the method throw an ArgumentOutOfRangeException too:

  • The specified argument was out of the range of valid values. (Parameter ‘level’)

These are known exceptions, but unexpected exceptions can happen too. So be on the lookout for these.

How We Would Do It

Alright, we have 3 possible ArgumentExceptions, one ArgumentOutOfRangeException, and maybe some possible Exceptions. Most people will write the try-catch like this:

try
{
    Method(1, "ai", -10);
}
catch (ArgumentOutOfRangeException ae)
{
    // Do something
}
catch (ArgumentException aoore)
{
    if (aoore.Message.Contains("ID cannot be 0"))
    {

    }
    else if (aoore.Message.Contains("name of the user is too short"))
    {

    }
    else if (aoore.Message.Contains("department on the new user"))
    {

    }
    else
    {
        // No idea, good luck.
    }

    // Do something
}
catch (Exception ex)
{
    // Yeah, I don't know it either... 
}

This isn’t wrong, but it can mess up the readability of the code a lot. We can use exception filters to clear up the code, make it more readable, and get rid of the if-statements.

Using Exception Filters

Using a filter on exceptions makes it easier to understand and read what is happening. We can designate a specific catch for a specific exception with a specific body. We can pinpoint to an exact situation and act accordingly.

Using a filter we can use the exception’s properties to be as specific as we want. In the example above we can create a catch specially made for the ArgumentException with the text “The name of the user is too short”. I would look like this:

catch (ArgumentException aoore) when (aoore.Message.Contains("The name of the user is too short"))
{

}

The when is the start of a condition, which has to be true for the catch to work. If the condition is false, the code moves to the next catch, unless there isn’t any.

If I would complete the complete try-catch in the previous example it would look like this:

try
{
    Method(1, "ai", -10);
}
catch (ArgumentOutOfRangeException ae)
{
    // Do something
}
catch (ArgumentException aoore) when (aoore.Message.Contains("name of the user is too short"))
{
    // Do something
}
catch (ArgumentException aoore) when (aoore.Message.Contains("ID cannot be 0"))
{
    // Do something
}
catch (ArgumentException aoore) when (aoore.Message.Contains("department on the new user"))
{
    // Do something
}
catch (ArgumentException aoore)
{
    // This one is used when an ArgumentException is thrown, but the previous filters are not met.
}
catch (Exception ex)
{
    // Yeah, I don't know it either... 
}

This looks a bit cleaner and gives more oversight on the try-catch.

Another Example

You don’t have to check the message in the condition, you can use other properties in the exception too. You can even combine them using the or (||) or and (&&) operators.

When you are working with online tasks, like a web scraper or just the HTTPClient, you might want to catch the HttpRequestException. This one is used to throw an exception when something goes wrong when requesting online requests.

The HttpRequestException has a StatusCode, which can be 500, 400, 404, 401, 200, 201, etc. When something goes wrong and the HttpRequestException is thrown you might want to filter on the StatusCode:

try
{
    //Try statements.  
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
    Console.WriteLine("The end point you are trying to reach cannot be found. Please check the URL");
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized || ex.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
    Console.WriteLine("You are not authorized to call this end point. Please login or show some credentials.");
}
catch (HttpRequestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
    Console.WriteLine("Something went wrong on the server. Please try again later.");
}
catch(Exception ex)
{
   // Other exceptions
}

These are just Console.WriteLines, but the unauthorized and forbidden could send back a redirect to a login page, for example.

If the HttpRequestException throws a different StatusCode or the method in the try throws a completely different exception, the last catch will be used.

Conclusion

Exception filters can make your code easier to read and better to maintain. Although you need to be careful not to go berserk on all kinds of exceptions in a try-catch, it can help you pinpoint specific exceptions.

I think the idea behind filters on exceptions is a great addon in working towards better maintainable and readable code. But at the end of the day, it is the developer that makes sure of that… Or not.

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

Table Of Contents
Kens Learning Curve