Options for Configuring ASP.NET Core Application Settings

With all of the controversy around project configurations within .NET Core, one thing that has managed to be consistently JSON-based has been the use of application settings configuration files in this new world. While JSON does read incredibly easily, it can very quickly become muddled if you are storing large, complex objects consisting of nested objects and arrays, each with multiple properties of different types, and so on.

Thankfully, you have options. And I don't mean options like going to use XML, I mean that there's a specific framework designed to tackle issues like these and make working with these potentially cumbersome configurations much more manageable.

Enter the Options Framework

The Options framework is a very basic framework that is specifically designed to handle accessing and configuring POCO settings within .NET Core, and it simply couldn't be easier to work with.

Now let's say that you have a configuration file for your application that looks like the following:

{
    "ApplicationLayout": {
        "LayoutChangingEnabled": true,
        "Layouts": [
            {
                "Name": "Standard",
                "Modules": [
                    {
                        "Name": "Foo",
                        "Order": 1
                    },
                    {
                        "Name": "Bar",
                        "Order": 2
                    }
                ]
            },
            {
                "Name": "Detailed",
                "Modules": [
                    {
                        "Name": "Foo",
                        "Order": 1
                    },
                    {
                        "Name": "Bar",
                        "Order": 2
                    },
                    {
                        "Name": "Admin",
                        "Order": 3
                    }
                ]
            }
        ]
    }
}

It's fairly simple. But if you wanted to access any of the individual items, it could potentially get pretty hairy drilling down into nested elements and muddle up your code. Thankfully, this is where the Options framework really shines.

Options will allow you to define a C# class to represent your configuration settings, and it will handle actually binding your existing JSON configuration to this class with just a single line of code. Let's see what this structure might look like for our previous example:

public class ApplicationConfiguration
{
    public ApplicationLayout Layout { get; set; }            
}
 
public class ApplicationLayout
{
    public bool LayoutChangingEnabled { get; set; }
    public Layout[] Layouts{ get; set; }
}
 
public class Layout
{
    public string Name { get; set; }
    public Module[] Modules { get; set; }
}

public class Module
{
    public string Name { get; set; }
    public int Order { get; set; }
}

Now all that we need to do is simply include the Options NuGet package within our application:

Install-Package Microsoft.Extensions.Options

And then within the Startup.cs file, we can read our configuration file in as expected:

var config = new ConfigurationBuilder()
    .AddJsonFile("YourConfigurationFile.json")
    .Build();

And then simply wire up an IOptions service that will allow your strongly-typed configuration to now be injected as a service anywhere within your application:

public void ConfigureServices(IServiceCollection services)
{
    // Omitted for brevity

    services.AddOptions();
    services.Configure<ApplicationConfiguration>(config);
}

With all of these measures in place, you can now simply inject your Options within various locations in your application, allowing you to cleanly access the data that you need from your configuration without drilling down through multiple layers or nested elements:

public class FooController
{
     private readonly ApplicationConfiguration _options;

     public FooController(IOptions options)
     {
          // Access your options here 
          var canChangeLayout = options.Layout.LayoutChangingEnabled; // "true"
     }
}

Depending on your scenario, you may want to potentially override one of the values present within your settings. This is very easy to do and simply requires the use of a delegate after the initial configuration as seen below:

public void ConfigureServices(IServiceCollection services)
{
    // Omitted for brevity

    services.Configure<ApplicationConfiguration>(config);

    // Update the configuration
    services.Configure<ApplicationConfiguration>(options =>
    {
        options.Layout.LayoutChangingEnabled = false;
    });
}

There are a variety of other more advanced use cases that you might find helpful depending on the complexity of your application such as using snapshots to detect configuration changes, binding to object graphs, and numerous other features which you can read more about in the documentation.

See Them In Action

The ASP.NET team and several members of the community have worked together to put examples of just about every type of configuration scenario on GitHub if you want to see how they look in action. I'd highly recommend browsing through them if you need to tackle some of the more advanced use-cases (e.g. using in-memory providers, snapshots, object graphs, etc.) within your applications.