Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs
Contact   •   Articles   •   Products   •   Support   •   Search
Ad-free experience sponsored by:
ASPOSE - the market leader of .NET and Java APIs for file formats – natively work with DOCX, XLSX, PPT, PDF, images and more

Strongly Typed Configuration Settings in ASP.NET Core


One of the first things I do whenever I start on a new project is to set up project level configuration. So it's no surprise as I'm starting to finally dig back into ASP.NET Core after the big re-org, the first thing I started with was configuration. Things have changed a bit since the last time I wrote about this subject (post forwarded to this one now) and things have thankfully gotten a little easier.

Pluggable Configuration

ASP.NET Core has a pluggable configuration system which supports a variety of different mechanisms for reading configuration data. It looks like it still doesn't support a way to write configuration data, but that's a topic for another day. In this post I'll talk specifically about adding strongly typed configuration values to your configuration using the built-in configuration providers - IOptions<T> in particular.

Add references

The first thing in adding strongly typed configuration is to add an additional configuration package that provides the support for strongly typed configuration classes.

The relevant package is Microsoft.Extensions.Options.ConfigurationExtensions added on the bottom in project.json:

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.0.0-rc2-3002702",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging.Debug": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0-rc2-final",
    
    
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0-rc2-final",
  },
  ...
}

The configuration extensions give you access to the required Configuration overload to map a strongly typed class to a configuration section in the configuration store.

Create a new Configuration Class

Next create a new class that will hold your configuration settings. The class can be a simple POCO class:

public class MySettings
{
    public string ApplicationName { get; set; } = "My Great Application";
    public int MaxItemsPerList { get; set; } = 15;
}

This is very simple example, but the class you create can be more complex, with nested properties and even lists and collection.

Hooking up the Configuration

Next we need to configure the Dependency Inject and register the new configuration class so it can map the configuration data to the actual POCO object.

Here's what you need for the strongly typed class to become available as a configuration object.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    // Add functionality to inject IOptions<T>
    services.AddOptions();
    
    // Add our Config object so it can be injected
    services.Configure<MySettings>(Configuration.GetSection("MySettings"));
    
    // *If* you need access to generic IConfiguration this is **required**
    services.AddSingleton<IConfiguration>(Configuration);
}

AddOptions() adds the basic support for injecting IOptions<T> based objects into your code filled with the configuration data from the store. You then register your actual configuration class and map it to the configuration section it should use to read the data from.

In this context a section of a JSON configuration file is a top level property as you'll see in the next step. In Environment variables a section would be separator level based on the separator character (: or __).

Injecting IConfiguration

This is unrelated to using the strongly typed class and IOptions, but when you need inject a more generic IConfiguration for using string based configuration, make sure to explicitly register IConfiguration with the DI system. If you don't you get this error:

InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Configuration.IConfiguration' while attempting to activate 'WebApplication8.Controllers.ConfigurationController'.

Adding services.AddSingleton<IConfiguration>(Configuration) fixes this issue.

Adding configuration values to Appsettings.json

Let's assume you use the default configuration that gets set up in a new project like this:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddEnvironmentVariables();
        
    Configuration = builder.Build();
}

This results in configuration settings being stored in appsettings.json with potential override files for a the given environment (ie. appsettings.production.json).

You can now add your custom options below the root as a nested object in appsettings.json:

{
  "MySettings": {
    "ApplicationName": "My Very First MVC Application",
    "MaxItemsPerList": 10
  },  
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

As mentioned in the previous setting, the name you specify in GetSection("MySettings") maps to a top level property in the JSON file. Anything below is pulled into your configuration object when the configuration is read.

Accessing the Strongly Typed Configuration in an MVC Controller

In order to use the newly created configuration section we now have to inject the configuration data into the controller. There are a couple of ways to get at the configuration data:

  • Using the IOptions strongly typed object
  • IConfiguration.GetValue()

Let's look at the strongly typed resources first.

[Route("api")]
public class ConfigurationController : Controller
{
    private MySettings MySettings { get; set; }

    public ConfigurationController(IOptions<MySettings> settings)
    {            
        MySettings = settings.Value;
    }
           

    [HttpGet("appname")]
    public string AppName()
    {
        return MySettings.ApplicationName;
    }

    [HttpGet("maxlistcount")]
    public int MaxListCount()
    {
        return MySettings.MaxItemsPerList;
    }
}    

Start by creating a constructor that injects IOptions<MySettings> which gives you the the configured MySettings object via the .Value property and store it in a private property.

In the actual controller methods you can now access the configuration object using simple strongly typed property values as you'd expect.

Nice!

Using String Configuration Values

You can also access your the configuration data directly using string identification without the strongly typed object, by using the IConfiguration provider.

Plain IConfiguration access can be useful if you just want to add values to your configuration file without explicitly creating a mapping object and if you need to reload your configuration without restarting.

To do this add a Configuration property and pass an IConfiguration instance into the Controller's constructor:

[Route("api")]
public class ConfigurationController : Controller
{

    private IConfiguration Configuration { get; set; }
    private MySettings MySettings { get; set; }

    public ConfigurationController(IOptions<MySettings> settings, IConfiguration configuration)
    {            
        MySettings = settings.Value;
        Configuration = configuration;
    }
           

    [HttpGet("appname")]
    public string AppName()
    {
        return MySettings.ApplicationName;
    }

    [HttpGet("maxlistcount")]
    public int MaxListCount()
    {
        return MySettings.MaxItemsPerList;
    }


    [HttpGet("appname_key")]
    public string AppNameKey()
    {
        return Configuration.GetValue<string>("MySettings:ApplicationName");            
    }

    [HttpGet("maxlistcount_key")]
    public int MaxListCountKey()
    {
        return Configuration.GetValue<int>("MySettings:MaxItemsPerList");
    }
}

Refreshing Configuration Values

Unlike standard ASP.NET applications, ASP.NET Core applications don't automatically refresh the configuration data when the data is changed in the configuration store.

This means if you make a change while the application is running, you either need to restart the application, or explicitly refresh the configuration values.

However, the Configuration API does includes a IConfigurationRoot::Refresh() method that can be called and this works to refresh values if the source can refresh these values.

You can add this method somewhere in your Admin API if and invoke it when you make changes through a Web interface for example.

To use the Reload() functionality:

Add Configuration

In the ConfigureServices() method add:

services.AddSingleton<IConfigurationRoot>(Configuration);   // IConfigurationRoot
services.AddSingleton<IConfiguration>(Configuration);   // IConfiguration explicitly

to add allow IConfigurationRoot to be injectable. Next you need to add it to the control to be actually injected:

private IConfiguration Configuration { get; set; }
private MySettings MySettings { get; set; }
private IConfigurationRoot ConfigRoot { get; set; }

public ConfigurationController(IOptions<MySettings> settings, IConfiguration configuration,IConfigurationRoot configRoot)
{            
    MySettings = settings.Value;
    Configuration = configuration;
    
    ConfigRoot = configRoot;
}

And finally you can access the config root somewhere in your controller:

[HttpGet("reloadconfig")]
public ActionResult ReloadConfig()
{
    ConfigRoot.Reload();

    // this should give the latest value from config
    var lastVal = Configuration.GetValue<string>("MySettings:ApplicationName");
    
    return Ok(lastVal); 
}

This works to refresh the string based configuration value access via IConfiguration.

Unfortunately it does not work for the strongly typed value because that value is read on startup, stored and then not updated again. So the following will not refresh:

var lastVal = Mysettings.ApplicationName;
return Ok(lastVal); 

I haven't found a good way to do a refresh the strongly typed value short of a stop/start cycle for the application.

Summary

ASP.NET Core finally bakes in support for strongly typed configuration objects, which is nice as it removes the need to rely on a separate solution for this functionality as I had been doing (using my Westwind.Configuration library). The native support doesn't provide all of those features - specifically no support for writing and reliably reloading the config store - but it does provide the strong typing and relatively easy way to use different, pluggable providers which is good enough for more most applications.

I use strongly typed configuration extensively in every application, and I'm glad to see this functionality baked in natively. The easier it is to access configuration values, the more likely it is you end up building a configurable application. Go (con)figure...

Posted in ASP.NET Core  C#  ASP.NET  

The Voices of Reason


 

Andrew Lock
May 23, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Nice post! Particularly useful point about injecting the IConfiguration. I actually wrote a similar post the other day and missed that as a possibility to access the raw configuration.

I was more focused on the properties of your strongly typed configuration models that don't bind correctly : http://andrewlock.net/how-to-use-the-ioptions-pattern-for-configuration-in-asp-net-core-rc2/

It's interesting that the settings don't refresh automatically - my understanding of the 'reloadOnChange' parameter of AddJsonFile() was that it would do just that! Is that not the case? Or is it just that that only works for this particular FileProvider rather than the whole configuration in general.

Again, great post!

Rick Strahl
May 23, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

@Andrew - "reloadOnChange" is not working for me. I haven't checked closely in what scenarios it might work - it's not working when running through IIS express at least.

IConfiguration injection - yeah I had a back and forth on that with David Fowler yesterday. It seems odd to me that this is not available by default without having to explicitly add it to the DI provider. Seems like a pretty crucial component you'd need just about anywhere in the application if you're managing configuration correctly. Oddly IOptions<T> doesn't need anything and it probably depends on IConfiguration to read that data - yet still it's not injectable by default unless you explicitly add it.

The problem I have with that is that if you have sub-components that may depend on configuration, you are dependent on developers explicitly adding IConfiguration somewhere in their service config. If they don't - a sub-component can't get at IConfiguration cause it's simply not registered which is a real sucky situation IMHO.

Andrew Lock
May 23, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

@Rick - yeah I agree RE developers needing to explicitly add the IConfiguration, though I guess it's an attempt to drive all access to configuration through strongly typed config classes?

There appear to be a lot of closed issues relating to reloadChanges not working properly cross platform and so being removed, but I haven't dug in to what the state of play is now. Maybe was too difficult to do reliably cross platform so was pulled out, so maybe that overload will disappear too..

KRDM
May 25, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Saved my bacon. Been fighting this for a few days now. Thanks!

Mike-EEE
June 09, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

SO GREAT to see the thinking here in getting a more POCO-based approach to configuration. As great as project.json was, it was rooted in the friction and error-prone approach that both .NET Configuration and MSBuild suffer from: document-model-mapping-to-POCO, which creates unnecessary artifacts and makes it more difficult for tooling (and thus the end developer).

There are a few open GitHub issues/discussions that are taking place to move MSBuild and the new Roslyn-based project system to a new POCO-based model. It would be AWESOME to get your feedback and/or support here:
https://github.com/Microsoft/msbuild/issues/613
https://github.com/dotnet/roslyn-project-system/issues/37

Thank you for any consideration and support -- and for making this great article!

Raman
June 11, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Can you please provide some scenarios on how you use strongly typed configuration in your application?

Rick Strahl
June 11, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

@Raman - everywhere! Anything that's configurable in my application I tend to store in a configuration setting. ConnectionStrings, Folder locations, Operational Options, defaults etc.

Thanh
June 23, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Hi Rick,

I try this on RC 2 and it does not recognise Configuration in the following statement, what packages or namespace needed to be added?

// Add our Config object so it can be injected
    services.Configure<MySettings>(Configuration.GetSection("MySettings"));


Thanks

Rick Strahl
June 23, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Uhm did you read the post? Microsoft.Extensions.Options.ConfigurationExtensions

Andrew Lock
June 23, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

@Rick - I finally got round to looking in to the 'reloadOnChange' aspect of the configuration files - it turns out this does work, it's just rather obfuscated! I wrote a post on it here: http://andrewlock.net/reloading-strongly-typed-options-when-appsettings-change-in-asp-net-core-rc2/.

The tl;dr; version is that 'reloadOnChange' does seem to work to reload the raw IConfigurationRoot. In order to reload Options, you need to inject IOptionsMonitor<T> instead of IOptions<T>, and register a callback on the IOptionsMonitor<> you want to reloaded with config changes.

Unfortunately, while this works on RC2, it has since been removed, but will be back post 1.0!

Vitaliy
July 07, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Hello, @Rick. You can look at my solution for autoreload strongly typed configuration at http://net-nts.blogspot.ru/2016/07/autoreload-strongly-typed-configuration.html

Giuseppe
July 08, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Hi all, @Rick. Your implementation from this post used to work in my team project on RC1. Now we're migrating to RTM and we find the following issue: 'configuration.GetSection("someTopLevelKey")' returns null. When I try 'configuration.GetKey("someTopLevelKey:propertyKey")' the value is returned, so configuration source are set correctly (thanks to 'SetBasePath()' too).

Besided that method, there used to be also a 'configuration.Get<SomeConfigClass>("someTopLevelKey")' which is not there anymore. We tried replacing with 'GetValue<>()' and it returns null as well.

Does anyone know how to grab a whole section of e.g. appsetting.json, and map it to correspondent strongly-typed POCO configuration class?

TA

Sapan Desai
July 12, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Hi Rick, Nice post. Thanks. I am wondering how I could make use of this feature in my unit / integration tests where there is NO application Startup.cs. One way that I am trying to do is as follows (below code is straight out of one of the unit / integration test methods):

var settings = Options.Create(new ProductApiSettings());
var productAPIUrl = settings.Value.ApiUri;

But during the test execution, when I look at the value of "productAPIUrl", it is still null. Even though I have an appsettings.json file as follows:

{
"ApiUri": "http://<<productAPI URL>>"
}

Chris
July 31, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Hi Rick

Thanks for all these articles, really useful.

Re: the strongly typed object ("MySettings" in your example above) and it not updating automatically....

I have done a couple of quick tests in the Azure App Service. In the Azure Portal under application settings I added the setting key (e.g. MySettings:ApplicationName in your example). When the settings are saved in the portal, it appears that the application is restarted. Therefore, both mechanisms for getting the setting values (i.e. strongly typed object and string config) will give the updated values.

Chris

Uli Weltersbach
August 17, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Hi Rick,

I'm having the same issue as Raman:
The namespace "Microsoft.Extensions.Options.ConfigurationExtensions" doesn't exist in Core 1.0.0 and hence there's no method signature that allows me to call "services.Configure<MySettings>(Configuration.GetSection("MySettings"));"
Could you explain exactly which package you get "Microsoft.Extensions.Options.ConfigurationExtensions" and the extension method from?
Is it really still the same (I just recently upgraded to Core 1.0.0 so I might be missing something)?

// Uli

Andrew
August 18, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Hi @Guiseppe,

You can load it in to the configuration class like so:

var config = new Settings();
Configuration.GetSection("Settings").Bind(config);


I use this approach to inject the configuration class directly in to my IOC container in order to avoid the IOptions<> cruft

mejobloggs
September 17, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Can I access MySettings from a razor file?

I'm used to having MySettings as a static class and been able to access it anywhere by doing MySettings.MyValue

Can't figure out how to use the method in this tutorial in a razor view

Blake
October 12, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

You really missed the boat on a very important bit of documentation:

Within your controller, you need to add the following Using statement:

using Microsoft.Extensions.Options;

Rick Strahl
October 12, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

@Blake - yeah - getting the right package references is probably the most painful thing about ASP.NET Core for me. Since most things are extension methods they are not easily discoverable, and it just looks like this stuff isn't there. Relying so heavily on extension methods is a Design flaw IMHO.

Nigel Belham
November 21, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

Hi Rick. RE "Adding services.AddSingleton(Configuration) fixes this issue."

Using ASP.NET Core I found that I had to specify the IConfigurationRoot Interface.

services.AddSingleton(Configuration); Which can be simplified to... services.AddSingleton(Configuration); Hope this helps.

Richard
November 25, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

How do we enable an injection of the option setting object to a data access layer in a separate project, without using IOption<>?


Wade
December 31, 2016

# re: Strongly Typed Configuration Settings in ASP.NET Core

I noticed a few people talking about hot loading/hot swapping configs in the comments section. Essentially the IOptionsMonitor interface got added, removed, then readded so you can still use this way but it requires a bit of code to get going. Microsoft have also added the IOptionsSnapshot interface though, and this is how they recommend doing reloadable configuration. Instead of injecting IOptions into your class, you now inject IOptionsSnapshot and it will inject the latest settings (At time of instantiation).

That last part is important as if you have a singleton class, the settings won't be "hot swapped" inside it. It's only when the class is built and IOptionsSnapshot is requested from the services collection will it then get the "latest". I wrote a bit about it here : http://dotnetcoretutorials.com/2017/01/01/hot-swapping-custom-configurations-asp-net-core-using-ioptionssnapshot/


Sean Fackrell
Sunday

# re: Strongly Typed Configuration Settings in ASP.NET Core

In case anyone stumbles on this one. You can't use 'IEnumerable' or 'IList' in your config POCO as you can with normal JSON deserialization. If you do, you'll get an InvalidOperation exception when you resolve IOptions. You have to use List instead or presumably a type that can be constructed. i.e.

// This works
public class AppSettings
{
    public List<ApplicationUser> SeedUsers { get; set; }
}

but

// This doesn't
public class AppSettings
{
    public IEnumerable<ApplicationUser> SeedUsers { get; set; }
}

This was using configuration with dependency injection a la

services.Configure<AppSettings>(Configuration);
services.Configure<AppSettings>(Configuration.GetSection(nameof(AppSettings)));

// and then resolved later by the IoC container
IOptions<AppSettings> _settings

with JSON

{
  "AppSettings": {
    "SeedUsers": [
      {
        "UserName": "user1",
        "Email": "user1@gmail.com"
      },
      {
        "UserName": "user2",
        "Email": "user2@gmail.com"
      }
    ]
  }
  }

 

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2017