TIL: Always check for missing configuration values inside constructors
Tags: todayilearned, csharp, dotnet
Published: 2022-12-07 15:04:03

_I originally published this post on [my blog](https://canro91.github.io/2022/12/02/ValidateInputParameters/). It's part of my personal [C# Advent of Code](https://canro91.github.io/AdventOfCode2022)._

This is a lesson I learned after trying to use a shared NuGet package in one of my client's projects and getting an `ArgumentNullException`. I had no clue that I needed some configuration values in my `appsettings.json` file. This is what I learned.

**Always check for missing configuration values inside constructors. In case they're not set, throw a human-friendly exception message showing the name of the expected configuration value. For example: 'Missing Section:Subsection:Value in config file'.**

## A missing configuration value

This is what happened. I needed to import a feature from a shared Nuget package. It had a method to register its dependencies. Something like `services.AddFeature()`.

When calling an API endpoint that used that feature, I got an `ArgumentNullException`: _"Value cannot be null. (Parameter 'uriString')."_ It seemed that I was missing a URI. But what URI?

Without any XML docstrings on the `AddFeature()` method, I had no other solution than decompile that DLL. I found a service like this one, 

```csharp
public class SomeService : ISomeService
{
    private readonly Uri _anyUri;

    public SomeService(IOptions<AnyConfigOptions> options, OtherParam otherParam)
    {
        _anyUri = new Uri(options.Value.AnyConfigValue);
        //                ^^^^^^^
        // System.ArgumentNullException: Value cannot be null. (Parameter 'uriString')
    }

    public async Task DoSomethingAsync()
    {
        // Beep, beep, boop...
        // Doing something here...
    }
}
```

There it was! The service used the [IOptions pattern to read configuration values](https://canro91.github.io/2020/08/21/HowToConfigureValues/). And I needed an URL inside a section in the appsettings.json file. How was I supposed to know?

<figure>
<img src="https://source.unsplash.com/5B0IXL2wAQ0/600x400" alt="Black and brown jigsaw puzzle" />

<figcaption>Missing one value... Photo by <a href="https://unsplash.com/@sigmund?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Sigmund</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></figcaption>
</figure>

## A better exception message

Then I realized that a validation inside the constructor with a human-friendly message would have saved me (and any other future developer using that NuGet package) some time. And it would have pointed me in the right direction. I mean having something like,

```csharp
public class SomeService : ISomeService
{
    private readonly Uri _anyUri;

    public SomeService(IOptions<AnyConfigOptions> options, OtherParam otherParam)
    {
        //  vvvvvvv
        if (string.IsNullOrEmpty(options?.Value?.AnyConfigValue))
        {
            throw new ArgumentNullException("Missing 'AnyConfigOptions:AnyConfigValue' in config file.");
            //                              ^^^^^^^^
            // I think this would be a better message
        }

        _anyUri = new Uri(options.Value.AnyConfigValue);
    }

    public async Task DoSomethingAsync()
    {
        // Beep, beep, boop...
        // Doing something here again...
    }
}
```

Even better, what if the `AddFeature()` method has an overload that receives the expected configuration value? Something like `AddFeature(AnyConfigOptions options)`. This way, the client of that package could decide the source of those options. Either read them from a configuration file or hardcode them.

The book "Growing Object-Oriented Software Guided by Tests" suggests having a `StupidProgrammerMistakeException` or a specific exception for this type of scenario: missing configuration values. This would be a good use case for that exception type.

Voilà! That's what I learned today: always validate configuration values inside constructors and use explicit error messages when implementing the Options pattern. It reminded me of _"The given key was not present in the dictionary"_ and other obscure error messages.

Have you found obscure exception messages recently? Do you write friendly and clear error messages?

Stay tuned to my [C# Advent of ~~Code~~ Posts](https://canro91.github.io/AdventOfCode2022).

***

_Hey, there! I'm Cesar, a software engineer and lifelong learner. Visit my [Gumroad page](https://imcsarag.gumroad.com) to download my ebooks and check my courses._

_Happy coding!_