Validate strongly typed options when using config sections

Kees C. Bakker
wehkamp-techblog
Published in
3 min readSep 20, 2019
Sometimes you need to validate what’s in the box.

I like to validate my application configuration upon startup. Especially when doing local development, I want to know which application settings are missing. I also like to know where I should add them. This blog shows how to implement validation of your configuration classes using data annotations.

Use data annotations

The configuration classes were completely rewritten when .NET Core was introduced. We came a long way since the old .config files.

I love how we can now use the options pattern to bind our settings classes. Strongly typed instances are injected as IOptions<T> or IOptionsSnapShot<T> into our services.

Let’s define a settings class and use data annotations to make the fields required:

In ASP.NET we already use data annotation to validate our models. Some better known attributes are: Required, MinLength, MaxLength, Range, StringLength, EmailAddress, Url and RegularExpression.

What does .NET Core provide?

Microsoft introduced a validation method that can validate the options (since .NET Core 2.2). You can use it with data annotations and it can look something like this:

This is what happens when you try to read the Value of the IOptions<T>object:

An error is thrown inside the code that tries to use the provided option. It is validated when the valid is accessed.

.NET throws an error upon usage and the error message does not provide many clues on what to do or where to look.

If you, like me, are looking for eager validation on startup, you must wait until the next version:

Eager validation (fail fast at startup) is under consideration for a future release.
Source: Options pattern in ASP.NET Core — Options Validation

So, we need to code something our selves.

PostConfigure to the rescue!

Let’s use PostConfigure to validate the created option and throw an error if something is invalid:

Now, when we run the code, it breaks in (and during) Startup.cs. This is eager validation, and it provides us with an exception that helps to solve the configuration-error.

The application now breaks in the right time + place and with a useful error message.

Extension methods

Your startup can get quite verbose if you have to configure many options in your application. That’s why I’ve created the following extension methods to help set up the configuration and validation of options:

Coming up with a good name for an extension method is usually the hardest part. Normally, I set up options using services.Configure<KafkaOptions>(Configuration.GetSection("Kafka")), so ConfigureAndValidate<KafkaOptions>("Kafka", Configuration) looks good to me.

Example application

Let’s look at an example application. I like to use the appsettings.json to define the configuration of my services. This is the Program.cs:

This setup allows us to use environment-specific configuration files. Next, we’ll set up the loading of the configuration information into an object in the startup.cs:

Note: the configuration is injected in the startup class.

Final thoughts

Because we’ve used config.AddEnvironmentVariables() in our program, the setting values could also come from the environment. Technically, we can add a Kafka__GroupId to satisfy the requirement.

Configuration can come from a myriad of places, not just from the config files. Pointing your fellow developers into the right direction can save a lot of time.

I work as a Lead Developer at Wehkamp.nl, one of the biggest e-commerce companies of the Netherlands. This article is part of our Tech Blog, check it out & subscribe. Looking for a great job? Check our job offers or drop me a line on LinkedIn.

Originally published at keestalkstech.com on September 20, 2019.

--

--

Kees C. Bakker
wehkamp-techblog

I work as a Lead Developer for one of the biggest web-shops in the Netherlands: wehkamp. I ❤️ C# and I like to solve nifty problems.