Configuration GetSection returns null value for object sections

Viewed 14767

Hello i am using a a json configuration file within a .NET Core App and i do not understand why i get the value null for subsections that are objects:

{
    "tt": {
        "aa":3,
        "x":4
    },
    "Url":333,
    "Config": {
        "Production": {
            "RedisAddress": {
                "Hostname": "redis0",
                "Port": 6379
            },
            "OwnAddress": {
                "Hostname": "0.0.0.0",
                "Port": 9300
            }
        },
        "Dev": {
            "RedisAddress": {
                "Hostname": "redis0",
                "Port": 6379
            },
            "OwnAddress": {
                "Hostname": "0.0.0.0",
                "Port": 9300
            },
            "Logger": "logger.txt"
        }
    }
}

When i try GetSection("Config") or GetSection("tt") i get the value null.It however returns the value for primitive types like in my case Url.

What is funny is that if i peek inside the configuration.Providers[0].Data i have all the content present like in the picture:

enter image description here

Why does it return null for object types?

Code

WebHostBuilder builder = new WebHostBuilder();
builder.UseStartup<Startup>();

string appPath = AppDomain.CurrentDomain.BaseDirectory;
string jsonPath = Path.Combine(Directory.GetParent(Directory.GetParent(appPath).FullName).FullName, "appsettings.json");

IConfiguration configuration = new ConfigurationBuilder()
    .SetBasePath(appPath)
    .AddJsonFile(jsonPath, optional: true, reloadOnChange: true)
    .Build();

var sect = configuration.GetSection("Config");//has value null
var sect2 = configuration.GetSection("tt");//has value null
var sect3 = configuration.GetSection("Url"); has value 333
4 Answers

There is nothing wrong in your example. The Value property you're referring to is a string, which is null for both your sect and sect2 variables simply because neither of these contain a string value - they are both objects, as you've stated.

If you want to pull out a value from e.g. sect2, you can do so using something like this:

var aaValue = sect2.GetValue<int>("aa");

There are a few more options for getting the values for a section like this. Here's another example that will bind to a POCO:

public class TT
{
    public int AA { get; set; }
    public int X { get; set; }
}

var ttSection = sect2.Get<TT>();

If all you want to do is get a nested value, there’s really no reason to use GetSection at all. For example, you can just do the following:

var redisHostname = configuration["Config:Dev:RedisAddress:Hostname"];

Both answers (TanvirArjel and Kirk Larkin) are correct. I am just going to clarify things for you and provide another way of getting the value form the configuration file.

To get a value from appsettings.json you need to pass the path of the value (colon-separated) to the configuration.

There are different ways to get the value without binding the section to a class. E.g.:

var aaAsString = configuration["tt:aa"]; //will return the value as a string "3".
//To get the actual value type you need to cast them 
var aa1 = configuration.GetValue<int>("tt:aa"); //returns 3.
var aa2 = configuration.GetSection("tt").GetValue<int>("aa");
var aa3 = configuration.GetSection("tt").GetValue(typeof(int), "aa");

var sect = configuration.GetSection("Config"); returns null because Config section has no key and value, instead it has a SubSection which is Production. Key and Value reside in the lowest level of this hierarchy.

Here is the details from Microsoft of reading appsettings.json file in ASP.NET Core.

According to the above documentation you need to do as follows to read the values from appsettings.json file:

var hostName = configuration.GetSection("Config:Production:RedisAddress:Hostname").Value; // will return the value "redis0" for key `HostName`
var port = configuration.GetSection("Config:Production:RedisAddress:Port").Value; // will return the value 6379 for key `Port`
var aa = configuration.GetSection("tt:aa").Value; // will return 3

Following the above methodology you can read any value from the appsettings.json file:

This if how I made it work

"Localization": {
  "DefaultCulture": "en-US",
  "SupportedCultures": [
    "en-US",
    "no-NB",
    "uk-UA",
    "ru-RU"
  ],
  "SupportedUICultures": [
    "en-US",
    "no-NB",
    "uk-UA",
    "ru-RU"
  ]
}
var localizationSection = this.configuration.GetRequiredSection("Localization");
options.AddSupportedCultures(localizationSection.GetRequiredSection("SupportedCultures").Get<string[]>());
options.AddSupportedUICultures(localizationSection.GetRequiredSection("SupportedUICultures").Get<string[]>());
options.SetDefaultCulture(localizationSection.GetRequiredSection("DefaultCulture").Get<string>());
Related