pantonis
pantonis

Reputation: 6487

configuration.GetValue list returns null

I am trying to read a list from appsettings.json file using the GetValue<T> method:

var builder = new ConfigurationBuilder().SetBasePath(System.AppContext.BaseDirectory)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

IConfigurationRoot configuration = builder.Build();
var rr = configuration.GetValue<IList<ConnectionSettings>>("Connections");


public class ConnectionSettings
{
    public string Name { get; set; }

    public string Host { get; set; }

    public string Account { get; set; }

    public string Password { get; set; }
}

and my appsettings.json

{
"Connections": [
    {
      "Name": "",
      "Host": "192.168.1.5",
      "Account": "74687",
      "Password": "asdsdadsq"
    },
    {
      "Name": "",
      "Host": "127.0.0.1",
      "Account": "45654",
      "Password": "asdasads"
    }
  ]
}

Problem is that I always get null and I dont understand why.

Upvotes: 61

Views: 57544

Answers (5)

Anushree
Anushree

Reputation: 211

Configuration.Get<T> is a better option when you have nested configuration using non-primitive structure like list or array.

{
  "Email": {
    "ToEmails": [
      "[email protected]",
      "[email protected]",
      "[email protected]"
    ]
}

List<string> emailTo = _config.GetSection("Email:ToEmails").Get<List<string>>()

foreach (string email in emailTo)
{
    sendGridMessage.AddTo(new EmailAddress(email));
}

OR use Bind()

public static class ConfigurationRootExtentions
{
    public static List<T> GetListValue<T>(this IConfigurationRoot configurationRoot, string section)
    {
        var result = new List<T>();
        configurationRoot.GetSection(section).Bind(result);
        return result;
    }
}

Ref[1]: https://blog.bitscry.com/2017/11/14/reading-lists-from-appsettings-json/
Ref[2]: https://github.com/aspnet/Configuration/issues/451

Upvotes: 19

Athanasios Kataras
Athanasios Kataras

Reputation: 26432

I have spotted the following issue on GitHub: GetValue<T> not working with lists

Long story short: It is by design.

So you can try this:

var result = new List<ConnectionSettings>();
var rr = configuration.GetSection("Connections").Bind(result);

Upvotes: 37

basquiatraphaeu
basquiatraphaeu

Reputation: 667

It might be useful for you.

GetValue<type>("key") does not work for complex types.

Let's say you have the following appsettings.json structure:

{
    "ArrayOfObjectsWithinObjects": [
        {
            "foo0": "bar",
            "foo1": 1,
            "foo2": false,
            "anotherObject": {
                "foo3.1": "3.1",
                "foo3.2": "3.2"
            }
        },
        {
            "foo0": "bar",
            "foo1": 1,
            "foo2": false,
            "anotherObject": {
                "foo3.1": "3.1",
                "foo3.2": "3.2"
            }
        }
        ...

    ]

}

and C# the appropriate classes

public class Foo
    {
        public string foo0 { get; set;}
        public int foo1 { get; set;}
        public bool foo2 { get; set;}
        public AnotherObject anotherObject { get; set;}
    }

 public class AnotherObject
    {
        public string foo3.1 { get; set; }
        public string foo3.2 { get; set; }
    }

You should be able to:

//using static System.Console;
//using System.Linq;
//using Microsoft.Extensions.Configuration;

   var _listOfFoos =  _config.GetSection("ArrayOfObjects")
                        .GetChildren()
                        .ToList()
                        .Select( x => new Foo
                                      {
                                         x.GetValue<string>("")
                                         x.GetValue<int>("")
                                         x.GetValue<bool>("")
                         x.GetSection("anotherObject").Get<AnotherObject>()                       
                                        });

        WriteLine(_listOfFoos.anotherObject.foo3.1);

Note that foo3.1 is an invalid c# syntax and was used for didactic purposes.

Upvotes: 1

Sandeep Shekhawat
Sandeep Shekhawat

Reputation: 695

If you develop a project from scratch i.e using the VS template then set the following properties for appsettings.json (Right-click on appsettings.json--> click on Properties ). After that update following property value.

Copy to output Directory: Copy always

Now, you can run the application and get value using GetValue method.

After that, You can reverse the same setting as pervious

Copy to output Directory: Copy if newer

Upvotes: 2

Matt DeKrey
Matt DeKrey

Reputation: 11942

According to the documentation for GetValue<>, it gets the value of a (single) key and converts it to the specified type. Unfortunately, it doesn't throw an error if the value can't be converted, which is the situation you're running into.

I believe that Get<> would be preferable in your situation.

var rr = configuration.GetSection("Connections").Get<IList<ConnectionSettings>>();

According to Get<>'s documentation, it:

Attempts to bind the configuration instance to a new instance of type T. If this configuration section has a value, that will be used. Otherwise binding by matching property names against configuration keys recursively.

This allows you to get the value directly or, if it can't find the property, it looks for nested objects that contain a matching property.

An alternative would be as @AthanasiosKataras says; use Bind<>. This is helpful when you might have a sparse configuration in which you want to overlay some values with either default or calculated values.

Upvotes: 55

Related Questions