36

I was following some examples for ASP.NET 5 and I got stumbled with how to properly read "nested" configuration values (if that is the proper term).

Here is relevant portion of config.json:

{
    "ApplicationName" : "OwNextApp",
    "AppSettings": {
        "SiteTitle": "OwNext"
    },
}

And relevant portion of HomeController.cs:

public IActionResult About()
{
    var appNestedNameFailed = _config.Get("AppSettings.SiteTitle");
    var appNestedNameSuccess = _config.Get("AppSettings:SiteTitle");
    var appName = _config.Get("ApplicationName");
    ViewBag.Message = string.Format(@"Your 
        APP NAME: {0};
        APP NESTED NAME FAILED: {1}; 
        APP NESTED NAME SUCCESS: {2}", 
            appName, appNestedNameFailed, appNestedNameSuccess);

    return View();
}

Value for appNestedNameFailed is empty (my initial try before research). And appNestedNameSuccess has value; after I did research and found in tests for Configuration (relevant code shown):

// Assert
Assert.Equal("IniValue1", config.Get("IniKey1"));
Assert.Equal("IniValue2", config.Get("IniKey2:IniKey3"));

Can someone explain why is this the case? Why would it make sense to use : over .? From my interaction with JSON data usually . notation works fine, e.g. How to access nested json data.

Also, I found similar SO question but this does not give explanation of why : was chosen.

4 Answers 4

40

That's the convention that we decided upon when we first created the configuration model. We started with json in mind and : is the delimiter there.

Anyways, if you don't want to worry about those conventions, I recommend using the ConfigurationBinder which binds a configuration to a model (a strong type object). Here are the tests on GitHub that can serve as example.

Sign up to request clarification or add additional context in comments.

Comments

25
using Microsoft.Extensions.Configuration;
using System.IO;

IConfigurationRoot configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .Build();

var connectionString = configuration.GetValue<string>("ConnectionStrings:DefaultConnection");

// or

var connectionString2= configuration.GetSection("ConnectionStrings").GetSection("DefaultConnection").Value;  

appsettings.json:

{
  "ConnectionStrings": {
    "DefaultConnection": "myconnection"
  },
}

3 Comments

I'm not sure "GetSection" should be in there twice for connectionString2 at the bottom of the first code section.
@PaulSchroeder You can stack .GetSection("sectionName") as many times as required - the path remains the same, with each section separated by a : character.
I think the stacked GetSection() calls are an acceptable way to accomplish the goal but it does ignore the most proper solution as provided by Victor in the accepted answer. After all, .NET built-in JSON parser works well and reads better than the stacked GetSection() calls in addition to less work under the hood.
1

Peering deep into the bowels of the JsonConfigurationFileParser source with blame on for the enter/exit methods that look at:

private void VisitJObject(JObject jObject)
{
    foreach (var property in jObject.Properties())
    {
        EnterContext(property.Name);
        VisitProperty(property);
        ExitContext();
    }
}

private void EnterContext(string context)
{
    _context.Push(context);
    _currentPath = string.Join(":", _context.Reverse());
}

private void ExitContext()
{
    _context.Pop();
    _currentPath = string.Join(":", _context.Reverse());
}

it seems that the ASP.NET team should leave more illuminating check-in comments :).

My best guess is that there could be data stored in the config.json file that would need to have a . in it, whereas : would be less common. For instance:

"AppSettings": {
    "Site.Title": "Is .NET getting faster?"
},

It's a bad example, but it seems reasonable that they wanted to be as "safe" as possible and use something outside of the norm. If you wanted to store a type's full name, that would also be slightly easier without needing to worry about a stray period.

"AppSettings": {
    "ImportantTypeName": "WebApp.CoolStuff.Helpers.AwesomeClass"
},

3 Comments

That seems reasonable, and is what I thought as well. But, I was hoping for something more enlightening. Thanks for looking into this.
Looking more at this config.json, I think that they chose : because that is used to nest data, e.g. "AppSettings": {. Anyway.
It is typical to nest objects in json with : since it denotes a key/value pair. As a result, it probably ended up being the most natural delimiter. Sorry I couldn't uncover a more official answer for you :).
1

Unsure when this was introduced, I'm using .net 8.

Suppose your appSettings.json looks like this:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "SomeGroupedSettings": {
    "Setting1": "Setting 1 value",
    "Setting2": 42
  }

}

And you have a matching class:

public class SomeGroupedSettings
{
    public string? Setting1 { get; set; }
    public int Setting2 { get; set; }
}

You can read into a strongly typed object by injecting your configuration (Microsoft.Extensions.Configuration.IConfiguration) like so:

var tmp = configuration.GetSection(nameof(SomeGroupedSettings)).Get<SomeGroupedSettings>();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.