Configuration.GetSection in Asp.Net Core 2.0 getting all settings
Asked Answered
P

6

40

I am trying to learn the various ways to retrieve configuration info so I can determine the best path for setting up and using configuration for an upcoming project.

I can access the various single settings using

var sm = new SmsSettings 
{
    FromPhone = Configuration.GetValue<string>("SmsSettings:FromPhone"),

    StartMessagePart = Configuration.GetValue<string>("SmsSettings:StartMessagePart"),

    EndMessagePart = Configuration.GetValue<string>("SmsSettings:EndMessagePart")
};

I also need to be able to count settings, determine values of certain settings etc. So I was building a parsing method to do these types of things and needed a whole section of the settings file, which is what I assumed GetSection did. Wrong.

appsettings.json :

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=TestingConfigurationNetCoreTwo;Trusted_Connection=True;MultipleActiveResultSets=true",
    "ProductionConnection": "Server=(localdb)\\mssqllocaldb;Database=TestingConfigurationNetCoreTwo_Production;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "SmsSettings": {
    "FromPhone": "9145670987",
    "StartMessagePart": "Dear user, You have requested info from us on starting",
    "EndMessagePart": "Thank you."
  }
}

This code:

var section = Configuration.GetSection("ConnectionStrings");

Returns these results:

Image 1: variable properties

Image 2: Drilling down into JsonConfigurationProvider

A few questions arise.

  1. Why is this returning 3 different JsonConfigurationProviders, one of which includes every setting in the appsettings.json file (shown in Image 2)
  2. Why isn't GetSection("ConnectionStrings") actuall doing just that, returning the sub children of the ConnectionStrings
  3. Given number 2, how do you actually just retrieve the children of ConnectionStrings ?
  4. Assuming a model ConnectionStrings, with one property, List Connections, can the section be converted to an object?
Pragmatist answered 22/11, 2017 at 11:1 Comment(7)
You should take some time and review the documentation. learn.microsoft.com/en-us/aspnet/core/fundamentals/…Strongbox
Those methods are meant to be used when setting up bindings to configuration. They are not for parsing.Strongbox
@Nkosi...read that obviously...I am aware I can retrieve the settings in the manner described in those docs, but the description of GetSection is "Gets a configuration subsection with the specified key" ... so I am not getting why the whole file is returned and not just the keys children. I should be able to do both var section = Configuration.GetSection("ConnectionStrings"); and var section = Configuration["ConnectionStrings"] and have it return the same thingPragmatist
You could review the source code on GitHub to understand how they coded them.Strongbox
I have reviewed all the code, tested a few dozen variants of retrieval and still find no way to receive the children of a parent from the appsettings file. GetSection returns an IConfigurationSection, which has Key, Path, Value properties, certainly GetSection("ConnectionStrings").Value should return the children, but doesn't. I can retrieve any individual settings using the Configuration["keyhere"] syntax so I know configuration itself is working.Pragmatist
Does this answer your question? How to read AppSettings values from a .json file in ASP.NET CoreAgentival
GetChildern() always sorts the list of child node, does anyone know why?Noni
L
38

according to this post

https://github.com/aspnet/Configuration/issues/716

  1. the GetSection("Name").Value will return null, you must use GetChildren to get the child items
  2. Bind will populate the properties aginst the provided object, by default it maps against public properties, look at the update to support private properties.
  3. try Get<T>() over bind, it will provide you a strongly typed instance of the configuration object

try a simple POCO of your class (no complex getter/setters, all public, no methods) and then take it from there

Update:
From .net core 2.1 BindNonPublicProperties added to BinderOptions, so if set to true (default is false) the binder will attempt to set all non read-only properties.

var yourPoco = new PocoClass();
Configuration.GetSection("SectionName").Bind(yourPoco, c => c.BindNonPublicProperties = true)
Leenaleeper answered 25/4, 2018 at 17:46 Comment(3)
In order for Bind to work you need to have the following package Microsoft.Extensions.Configuration.BinderMessy
If Get<T>does not return all elements in the config list/array it may be unable to parse one or more of your entries. In which case it will not give you an error, but merely return the elements it managed to parse correctly. In my case there was a datetime field in my class which expected dates in American format not European. This resulted in Get<List<myClass>> returning just the first entry in the list. I hope this will help anyone in a similar situation. Keywords: only first, not returning all, missingSylvanite
GetChildern() always sorts the list of child node, does anyone know why?Noni
S
42

I understand the answer has been accepted. However, providing proper example code, just in case anyone looking to understand a bit more...

It is quite straight forward to bind custom strong type configuration. ie. configuration json looks like below

{
  "AppSettings": {
    "v": true,
    "SmsSettings": {
      "FromPhone": "9145670987",
      "StartMessagePart": "Dear user, You have requested info from us on starting",
      "EndMessagePart": "Thank you."
    },
    "Auth2Keys": {
      "Google": {
        "ClientId": "",
        "ClientSecret": ""
      },
      "Microsoft": {
        "ClientId": "",
        "ClientSecret": ""
      },
      "JWT": {
        "SecretKey": "",
        "Issuer": ""
      }
    }
  }
}

and your C# classes looks like

public class SmsSettings{
    public string FromPhone { get; set;}
    public string StartMessagePart { get; set;}
    public string EndMessagePart { get; set;}
}

public class ClientSecretKeys
{
    public string ClientId { get; set; }
    public string ClientSecret { get; set; }
}

public class JWTKeys
{
    public string SecretKey { get; set; }
    public string Issuer { get; set; }
}

public class Auth2Keys
{
    public ClientSecretKeys Google { get; set; }
    public ClientSecretKeys Microsoft { get; set; }
    public JWTKeys JWT { get; set; }
}

You can get the section by GetSection("sectionNameWithPath") and then Convert to strong type by calling Get<T>();

var smsSettings = Configuration.GetSection("AppSettings:SmsSettings").Get<SmsSettings>();
var auth2Keys= Configuration.GetSection("AppSettings:Auth2Keys").Get<Auth2Keys>();

For simple string values

var isDebugMode = Configuration.GetValue("AppSettings:IsDebugMode");

Hope this helps...

Samp answered 14/2, 2020 at 2:52 Comment(0)
L
38

according to this post

https://github.com/aspnet/Configuration/issues/716

  1. the GetSection("Name").Value will return null, you must use GetChildren to get the child items
  2. Bind will populate the properties aginst the provided object, by default it maps against public properties, look at the update to support private properties.
  3. try Get<T>() over bind, it will provide you a strongly typed instance of the configuration object

try a simple POCO of your class (no complex getter/setters, all public, no methods) and then take it from there

Update:
From .net core 2.1 BindNonPublicProperties added to BinderOptions, so if set to true (default is false) the binder will attempt to set all non read-only properties.

var yourPoco = new PocoClass();
Configuration.GetSection("SectionName").Bind(yourPoco, c => c.BindNonPublicProperties = true)
Leenaleeper answered 25/4, 2018 at 17:46 Comment(3)
In order for Bind to work you need to have the following package Microsoft.Extensions.Configuration.BinderMessy
If Get<T>does not return all elements in the config list/array it may be unable to parse one or more of your entries. In which case it will not give you an error, but merely return the elements it managed to parse correctly. In my case there was a datetime field in my class which expected dates in American format not European. This resulted in Get<List<myClass>> returning just the first entry in the list. I hope this will help anyone in a similar situation. Keywords: only first, not returning all, missingSylvanite
GetChildern() always sorts the list of child node, does anyone know why?Noni
M
26

If you use GetSections() along with Bind() you should be able to create poco objects for your use.

var poco= new PocoClass();
Configuration.GetSection("SmsSettings").Bind(poco);

This should return to you a poco object with all the values set.

Motive answered 21/11, 2018 at 21:38 Comment(1)
What does GetSection and Bind do actually?Weka
O
6

If you use the Bind method on the object returned by GetSection, then this would bind the key value pairs within the section to corresponding properties of the object it has been bound too.

For example,

class ConnectionStrings {
  public string DefaultConnection { get; set;}
  public string ProductionConnection {get; set;}
}

..

var connectionStrings = new ConnectionStrings();
var section = Configuration.GetSection("ConnectionStrings").Bind(connectionStrings);
Ostrogoth answered 22/11, 2017 at 14:38 Comment(3)
@Rufus...You are close...You can't set Bind to a var. So remove the part left of = and now you Bind to connectionStrings...The problem there which doesn't help me is you have to already know exactly what strings are in the settings file to create the class to bind to. Im trying to see whats in the file and create a list of strings.Pragmatist
You could use an array.Ostrogoth
For example, create an object of type Connection with property ConnectionName and ConnectionString. Then create an object of type ConnectionArray with property as an array of Connection objects. Adjust your appsettings.json accordingly and bind the ConnectionArray instead. This should give you flexibility to have an unknown number of connection strings with access via the connection name.Ostrogoth
N
3

It works for me on .Net Core directly on Razor HTML:

@Html.Raw(Configuration.GetSection("ConnectionStrings")["DefaultConnectoin"]) <!-- 2 levels -->
@Html.Raw(Configuration.GetSection("Logging")["LogLevel:Default"]) <!-- 3 levels -->
@Html.Raw(Configuration.GetSection("SmsSettings")["EndMessagePart"]) <!-- 2 levels -->

Reference: https://www.red-gate.com/simple-talk/dotnet/net-development/asp-net-core-3-0-configuration-factsheet/

Nomo answered 3/12, 2019 at 23:21 Comment(1)
useful example for selecting sub-sectionsMcginnis
D
2

If you required any section with "GetSection" and (key,value), try this:

Configuration.GetSection("sectionName").GetChildren().ToList()

and get a Collection of keys with vallues, can manipulate with LinQ

Duggan answered 5/4, 2019 at 6:25 Comment(2)
This doesn't work in .NET Core. IEnumerable<IConfigurationSection> does not implement ToList().Lateritious
It works fine - System.Linq.Enumerable.ToList().Rood

© 2022 - 2024 — McMap. All rights reserved.