Creating a Bridge to your ASP.Net Core Configuration from your Controller or Razor Page (Part 3)

This is the third in my series of posts looking at how to remove the need for controllers and razor pages to have knowledge of the options pattern in ASP.Net Core.

If you have arrived here from a search engine or link, I would recommend reading the previous two posts which set the background before coming back to this post.

Creating a Bridge to your ASP.Net Core Configuration from your Controller or Razor Page (Part 1)

Creating a Bridge to your ASP.Net Core Configuration from your Controller or Razor Page (Part 2)

In Part 2, I looked at how a lambda expression could be used to act as a bridge between the IOptionsSnapshot and T by creating an additional DI service:

If all you are concerned with is ensuring that your controller or razor page does not need to refer to the options pattern, then this is a suitable solution.

However, you may have the need to do something more exotic with the configuration settings such as perform some transformation such as decrypting some data or would like to perform  a validation of the settings before invalid values get injected into a class. This is achievable using the lambda, but it becomes somewhat messy.

Instead, the approach I will describe in this post will be to split the MyAppSettings class from the previous post out into three parts:

  • An interface that defines the properties as read only values IMyAppSettings
  • A settings reader class, MyAppSettingsReader,  that implements the interface but also implements setters so that the values can be mapped into an instance by the Configure extension method
  • A bridge class, MyAppSettingsBridge, that takes the IOptionsSnapshot in the constructor and then presents itself as the interface by using the Value method to get the value that has been read from configuration.

The last part of the jigsaw is then to register the bridge as a transient service with the DI container. From therein, the controllers, razor pages and any other class that needs the settings will just need a parameter of type IMyAppSettings.

Splitting the Class Up

In the previous post, the MyAppSettings class looked like this:

We will now divide it up, starting with the interface:

Note that the properties have been defined as read-only. Given that the configuration source(s) are read only as far as the code is concerned ( JSON files, XML files, environmental variables etc.), it is unlikely you will have code that would change the values.

Then comes the two implementation of the interface:

The MyAppSettingsReader is a simple DTO that the Configure extension method can map the configuration settings to – and therefore does need setters as well as the getters.

This class does not strictly need to implement the interface as it is there simply to map settings from the configuration into an object. You could include other properties that may be components that will be combined as a value returned in a property exposed in the interface. E.g. say you have a property that is a database connection string.

The second class is the bridge itself, MyAppSettingsBridge which must implement the interface as it will be used in the DI container. Note the constructor takes IOptionsSnapshot as the parameter and then acts as the go-between for the properties for the interface.

In the example class above, the class is effectively doing the same as the lambda expression from the previous post by calling the Value property on the options object.

However, by using a class, you can add more functionality. Taking the database connection example again, you could have individual properties for the server name, the database name, etc. in the reader class which can be then passed as parameters into a connection string builder inside the bridge class whose result is then exposed as a ConnectionString property in the interface.

In my plans for another post, I will be showing how values could be encrypted in the configuration settings source and then decrypted by the bridge class.

Wiring It All Up

Now we have the interface, reader and bridge, it is time to wire it all up.

Firstly, we will set up the DI container to read the configuration into the reader. This will automatically create a DI service for IOptionsSnapshot. Next we register the bridge as a transient instance of the IMyAppSettings interface.

Why register as Transient?It is up to you really. If registered as a transient, then every call will get the latest version of the configuration injected into it from IOptionsSnapshot. 

If registered as a singleton, the IOptionsSnapshot does not reload the configuration on each request.

If you are not worried about having the ability to read the configuration without restarting the application, use the singleton and also change IOptionsSnapshot to IOptions so that the configuration monitor is not required.

Now we are all set with the DI container, so we can change our controller to take IMyAppSettings as the parameter to the controller.

The code for this post and the previous post is available on GitHub at https://github.com/configureappio/configurebridgedemo1

In the next post, I will look at injecting more functionality into the bridge to decrypt some settings before they get injected into the controller.

Creating a Bridge to your ASP.Net Core Configuration from your Controller or Razor Page (Part 2)

In my previous blog post, I set the scene to give some background as to the relative merits of using the Options pattern vs binding a configuration object to a singleton in the DI container.

To summarise

  • IOptionsSnaphot allows the configuration to be changed without having to restart the application in order for new requests to make use of the changed values. However, the DI container will present the configuration as IOptions or IOptionsSnaphot which means that any assembly that makes using of the configuration will need to refer to the Microsoft.Extensions.Options Nuget package. Some feel that this is an overhead and is harder to test than a reference to just T (where T is the bound configuration object)
  • Binding the configuration object T in the service setup and then storing it in a singleton allows method signatures to just use T as a parameter which is cleaner, but loses the ability to dynamically react to changes in the configuration (E.g. the appsettings.json being changed)

For this post, I originally planned to launch into a full blown discussion of creating a bridging class between the controller and the configuration setting object to mask the use of IOptions.

However, before doing that, I noticed a comment at the bottom of Rick Strahl’s blog post from Todd Menier pointing out that a very simple bridge could be created by using an anonymous function, which seemed a good way to start to describe the basics of creating a bridge between the controller and the configuration before going into the more complex implementation of using abstractions and classes.

Before getting into creating the bridge, a quick recap of why the bridge is required.

An Example of Out-of-the-Box IOptions implementation

Say you have a class called MyAppSettings that you want to bind configuration data to, you will have a class that looks like this:

Which in turn you add to your appsettings.json as this:

In order to wire up the two, you will have a Startup.cs class that looks like this:

The first important line is services.AddOptions() which is required for IOptions to work.

The second is services.Configure(Configuration.GetSection(“MyAppSettings”)) which takes the MyAppSettings section that has been read from the configuration sources (in our case appsettings.json, but this may have been overridden by other sources) and binds it to an instance of MyAppSettings.

Looking at the source code for Configure(IConfiguration config) shows that behind the scenes, two singletons are registered: ConfigurationChangeTokenSource and NamedConfigureFromConfigurationOptions.

The first of these monitors the configuration for changes and is used when a parameter is defined as being of type IOptionsSnaphot. This allows changes to be sent to the controller without the need to restart the application. The second handles binding the object that holds the configuration values as the class instance.

With the binding set up, in your controller, you can have a constructor that looks like this:

Note, that in order to receive the MyAppSettings instance, the constructor parameter must be either of type IOptions or IOptionsSnapshot. The difference being that the former only gets the settings as they were when the application started, but the latter reads the latest version of the settings even if they changed after the application has started.

It is this extra bit of orchestration that some people don’t like as it means that any unit tests must mock the IOptions interface and provide an implementation of the Value method to get to the MyAppSettings object that is actually of interest.

Now, if it was purely just about MVC controllers and razor pages, I am personally not too hung up on this. However, it becomes a bit more complicated if the configuration settings are required for the constructor of a class in some other assembly as it then means that the other assembly needs to have a reference to the Microsoft.Extensions.Options Nuget package. This in turn could start a dependency sprawl across multiple assemblies.

Intercepting with a Bridge

To avoid this, a bridge is required that can accept IOptions or IOptionsSnapshot as a parameter, but presents itself as MyAppSettings (or an abstraction of it).

In my next post, I intend to present a solution using a bridging class that can accept other parameters to do more than just abstract away from the options pattern, by adding functionality such as decryption.

In the meantime, a way of simply getting the options pattern out of the way is to add another service to the DI container, this time a transient that uses an anonymous lambda function to get the value out of the options pattern and present that (as suggested by Todd).

This then allows the controller (or any other class that needs access to the configuration settings) to just need the MyAppSettings class as the parameter:

This lets the DI container deal with the bridging and keeps the clients ignorant of the options pattern.

In the next post in the series, I look at moving from using the lambda to using a full bridging pattern

Creating a Bridge to your ASP.Net Core Configuration from your Controller or Razor Page (Part 1)

This post is intended to set the stage for a later post (though may become a series) I have planned in which I look at using the Bridge design pattern to break the immediate dependency on the Options pattern in a .Net Core application.

The pattern is used to bind configuration settings to an object rather than pollute code with references to the configuration directly. For those not familiar with the pattern, I recommend following the link above.

This topic became of interest to me after reading a couple of Rick Strahl’s blog posts in which he discusses binding configuration settings to objects.

In these posts, Rick looks at approaches to binding configuration sections to objects, initially by binding directly to a class and storing that class as a singleton which can then be injected into the controller (or Razor page), and then later comparing that approach to using IOptions<T> or IOptionsSnapshot<T> as advocated by the .Net team.

A comparison between the two is also looked at by Filip W in the post Strongly typed configuration in ASP.NET Core without IOptions.

In both these posts, the authors appreciate the benefits of IOptions allowing the configuration to be changed on-the-fly without having to restart the application (when using IOptionsSnapshot<T>) whereas, an application restart is necessary with a singleton, but are not keen on having to drag along the Microsoft.Extensions.Options package everywhere that the configuration object will be used and having to use IOptions in parameter definitions when what is really of interest is the object T. This is a theme that runs through several blog posts and StackOverflow questions.

Rather than repeat the same discussions here, the links above are provided as background reading to give a foundation for the content I intend to provide in my next post where I will look at creating an intermediary (or bridge) so that projects that have in interest in the configuration object do not have to have a direct dependency on taking an IOptions<T> parameter, but instead take an abstraction representing the configuration.

By bringing an intermediary into the mix, it will also allow for adding functionality such as early validation of the configuration before it is used and decryption of sensitive data.

This will be the focus of the next post.