Adding the Microsoft.Extensions.Configuration to a .NET Framework Project

This is the second of a series of posts on this topic. The first was a background and the console application I intend to hang this on.

In this post I will add the configuration extension to allow me to configure applications settings in a JSON file.

The first step is to download the source from my github if you want to code along or you can just download the finished change.

Adding JSON Configuration

Add the Microsoft.Extensions.Configuration.json NuGet package. We want the published version rather than the .NET 5 preview versions because we need to comply with .NET Standard 2.0 so the Core code will run on .NET Framework 4.7.2 and above.

(Technically 4.6.1 is the earliest to support .NET Standard 2.0 but I find there are too many transitive dependencies to fix up missing .NET Standard 2.0 requirements for my liking)

Add a JSON file to the project and set the properties to always copy the file to the output path.. I called mine ‘configuration.json’ but any name will do.

{
  "Demo" : {
    "Banner": "Hello world!",
    "Arguments" :  [ "first", "second", "third"] 
  }
}

Add a ConfigurationBuilder

The implementation pattern of the Microsoft.Extensions is to have a “builder” for the feature. This will add extensions and third party concrete implementations of the interfaces. For each extension Microsoft typically provide a default implementation and there may be several options that can decorate the implementation or be switched by configuration using a strategy pattern.

We will start with just the JSON and add to it later. Modify the Main class to build the configuration root interface.

private static async Task<int> Main()
{
   IConfiguration configuration = new ConfigurationBuilder()
           .AddJsonFile("configuration.json")
           .Build();

   return await Task.Run(() => DefaultVerb(configuration));
}

Consume the Configuration

The configuration is organised as a hierarchy with the builder returning the root as a IConfigurationRoot interface. This extends the IConfiguration interface with information about the providers, in our case the JSON provider, and a method to Reload the information from the providers.

The IConfiguration interface provides methods to access each Item using a key and to traverse the hierarchy by accessing the children of the current section or jumping to a specific section.

The keys for our JSON file take the form of <section>:<name> so accessing the “Demo” section and reading the “Banner” value can be done like so:

configuration["Demo:Banner"]

which will return the value type, in this case a string.

Accessing arrays of values is a bit more complex because the IConfiguration abstraction represents this as a section with each array element as a child IConfigurationSection which is basically a key value pair with a property for the path which can be used to directly access the configuration item. We can process this array of child items with a bit of LINQ

var args = configuration.GetSection("Demo:Arguments")
    .GetChildren()
    .Select(arg => arg.Value)
    .ToArray();

We can now replace the original code with something far more complex but at least it now uses a JSON configuration file to specify the parameters rather than taking them on the command line. It’s all a bit artificial I know. Sorry.

private static int DefaultVerb(IConfiguration configuration)
{
    var currentForeground = Console.ForegroundColor;
    try
    {
        Console.WriteLine(configuration["Demo:Banner"]);
        Console.ForegroundColor = ConsoleColor.Gray;

        // this is how to process a json array of literals from the config file
        var args = configuration.GetSection("Demo:Arguments")
            .GetChildren()
            .Select(arg => arg.Value)
            .ToArray();

        Console.WriteLine($"Verb: Default called with {string.Join(",", args)}...");
        return 0;
    }
    finally
    {
        Console.ForegroundColor = currentForeground;
    }
}

The code can be found in github as v0.0.0-alpha.2.

This is a pretty poor approach to using the configuration data but a quick google foo exercise suggests that the Options pattern is the way to bind this data to a type safe class. Andrew Lock has a blog post on this and I will cover it in my next post.

Published by badsoftwareday

A Software Engineer with more than 20 years experience

Leave a comment