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!

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
April 23, 2017

# 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"
      }
    ]
  }
  }


Gaz
June 19, 2017

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

Thanks for the article Rick. I've been looking to experiment with Core, but I'm used to code separation and class libraries for my data and logic where possible. In practice, this is great for sharing my libraries between multiple websites and services.

This would mean that my data context would sit in a class library, but the way the Core application settings work makes it quite difficult (or code heavy) to actually use the settings from my web application in the class library.

So far, passing through the settings from the web application to the class library on each method is the only way I've got it to work. It seems so much more work and complexity than the machine/web/app.config hierarchy.

Have you found a good way of actually using a class library that accesses properties of the application config (e.g. the ConnectionStrings)?


Kevin
June 19, 2017

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

Let's say I store my connection string in this appsettings.json file. What's the best way to access it via a data access class? I can easily retrieve the value in a Controller, but then do I have pass the configuration object to every class the controller uses so it can use the connection string to access data?

Thanks, Kevin


Rick Strahl
June 19, 2017

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

@Gaz - also struggling with this. The only way to really make this work is DI (ie. expose your component as DI provider accessible for the main app) or alternately rely on static vars to push the data through the application. Realistically the latter is basically what we do in classic .NET apps - the difference is that the configuration system was always there and it's not in .NET core until you startup DI and the rest of the .NET Core infrastructure.

If you ask me - this is a serious design flaw but it is what is. It's easier to use in the most common use cases - it's just a clusterfuck if you have generic .NET (not ASP.NET) components that depend on configuration.

The other problem is that the default DI container is dependent on ASP.NET - so if you want to use DI outside of ASP.NET in a standalone component you have to use a different DI container.

I've been thinking about creating a wrapper around configuration that makes that easier.


Stefano
June 30, 2017

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

What about strongly typed configuration in a multi tenant web application?

Suppose you have a generic platform config file and than you have a specific file per tenant with some override.

As I undedstood configuration are loaded on application start and stored at application level, am I wrong? So that means integrated configuration is not suitable for this scenario, or there is a way for dealing with it?

Thank you for any suggestion.


Rick Strahl
June 30, 2017

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

@Stefano - that's the way configuration in .NET has always worked really if you think about it. In full framework it was a static interface (ConfigurationManager. typically) and it's the same here.

Personally I think there are two kinds of configuration: System configuration and Application Configuration. The built-in configuration systems really address System configuration - that are essentially global settings. Application Configuration is specific to an application and that is often more dynamic.

In my apps I tend to separate those out as separate configuration objects. And in a multi-tenant app I think the data would be much better off stored in some sort of data store like a DB table. This sort of thing is best abstracted with something a little more high level than these simple property mappers. In the past I used Westwind.Utilities.Configuration for that, but you certainly can bake configuration directly into your application's domain model in a multi-tenant app.


Matthew Blott
October 10, 2017

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

Good blog post - I bookmarked it and keep referring to it. The reason for the comment is I've been playing around with appsettings and trying various configurations for production. Anyhow, by chance I found out appsettings.json is automatically loaded, I'm not sure many people are aware of this. I was playing with an example similar to the one above here and added some settings in the json file and called them from an API expecting an error to be thrown and to my surprise they were read correctly. I then dug a bit deeper and found 5 configuration providers are automatically loaded (the following was in the VS Code terminal) ...

Providers [IEnumerable]:Count = 5

[0] [IConfigurationProvider]:Microsoft.Extensions.Configuration.Memory.MemoryConfigurationProvider}

[1] [IConfigurationProvider]:Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider}

[2] [IConfigurationProvider]:Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider}

[3] [IConfigurationProvider]:Microsoft.Extensions.Configuration.EnvironmentVariables.EnvironmentVariablesConfigurationProv ider}

[4] [IConfigurationProvider]:Microsoft.Extensions.Configuration.CommandLine.CommandLineConfigurationProvider}

This is all a bit weird. I thought ASP.NET Core was only supposed to use what you specified ( unless these are what you might call 'sensible defaults').


Rick Strahl
October 14, 2017

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

@Matthew - I think this is new with ASP.NET Core 2.0 and the new default configuration defaults that it loads. In 2.0 they use common presets and adding configuration providers is one of the things that are set up by default. You can still do things manually if you prefer or remove providers during Configure() cycle.


Triwaters
November 03, 2017

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

Thank you, Rick, for laying out such a nice explanation for the differences (and relative strengths and weakness) involved between IOptions and IConfiguration. I find once again that a few well-beaten (if not all) paths lead to your blog.


Mario
November 07, 2017

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

Hi Rick, I have the same question as Kevin. I understand that I can access the appsettings in the controller and view, but how do I access appsettings in the models? Do I have to just pass the configuration settings from the controller to my models everytime?

public IActionResult Index(int id)
{
   Person model = new Person(id); // <-- How do I pass appsetting in here?
   return View(model);
}

In this example, the person model would retrieve a user from SQL based on ID so I would like to pass in the connection string from appsettings.


Rick Strahl
November 07, 2017

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

Either use DI or use a static object. The documentation has examples how to set up the singleton during application startup.

To use it then:

MyAppConfiguration.Current.SomeSettingsValue

Personally I prefer a static singleton that lives in the business layer for this and is available anywhere in the application, but you can accomplish the same with DI.

 

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