Strongly typed configuration in ASP.NET Core without IOptions<T>

There are several great resources on the Internet about using the new Configuration and Options framework of ASP.NET Core – like this comprehensive post by Rick Strahl.

Using strongly typed configuration is without a question a great convenience and productivity boost for the developers; but what I wanted to show you today is how to bind IConfiguration directly to your POCO object – so that you can inject it directly into the dependent classes without wrapping into IOptions.

POCO configuration with IOptions<T>

The typical IOptions<T> driven configuration setup would look like on the snippet below. To use this code, you also need to reference the Microsoft.Extensions.Options.ConfigurationExtensions package, which will expose the extension methods and will also bring in the options framework package as a dependency.

This will allow you to load up MySettings from appsettings.json into MySettings POCO.

However, using the options framework also means that your configuration is registered in the DI container as IOptions<MySettings>, and that’s how you will need to inject it.

This typically wouldn’t matter but it also means that you will need to reference the Microsoft.Extensions.Options package everywhere where you want to consume this configuration (that’s where IOptions<T> is defined).

In other words, your POCO configuration is not exactly POCO anymore, as it drags the extra dependency alongside it, as you always consume it like this:

It also doesn’t give you access to the POCO configuration instance straight away – it just buries it directly into the DI, so to access it immediately in the Startup class, you’d need to resolve it from DI.

EDIT: On top of that – as mentioned by Steven – the problem with IOptions<T> is that it will defer the evaluation of the configuration. This means that if your configuration file is incorrect, your app can crash later on, the first time IOptions<T>.Value is accessed, rather than at startup.

POCO configuration without IOptions<T>

You could, however, register the POCO configuration manually, and avoid the extra dependency on the options framework. This is shown below.

We are manually binding the configuration to the POCO, rather than having the options framework do it for us. This functionality is available in the Microsoft.Extensions.Configuration.Binder package, which needs to be referenced (it is not an extra dependency for us though, it is already referenced by the Microsoft.Extensions.Options.ConfigurationExtensions package). It also needs to be referenced only in the entry project (or your composition root).

We can now consume this extension method as follows:

And you can now use your POCO configuration from the DI simply by injecting it, without any external dependencies.

Another small limitation of the options framework is that the POCO configuration class must have a parameterless constructor, as the framework will try to instantiate it for us.

However, with our custom approach, we can control how our class is instantiated. We could write extra extension methods that either take in an already existing instance, or a delegate responsible for its creation.

We can now consume these extension methods as its shown on the next snippet, without having to worry about exposing a default constructor. The instance could be created upfront or on demand through the delegate.

This type of approach allows you to combine your POCO configuration classes with runtime data stretching beyond the configuration file – for example information you’d read from IHostingEnvironment.