简体   繁体   中英

Extracting custom object array from appsettings.json

I'm trying to bind appsettings file into a generic class, but currently I can't map List<object> values.

I have an appsettings.Development.json hierarchy like this:

{
    "AppSettings":{
        "ApplicationName":"FOO"
        "MyValues":[
            {
                "Name":"Tryout1",
                "QuestionCount": 7
            },
            {
                "Name":"Tryout2"
                "SettingName":"ABCDEFG"
            }
        ]
    }
}

And my generic class is like this:

public class AppSettings
{
    public string ApplicationName {get;set;}
    public List<object> MyValues {get;set;}
}

When I use below code to bind this appsettings.Development.json into the generic class like this:

static ConfigurationHelper()
{
    var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
    
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile($"appsettings.{environmentName}.json")
        .Build();

    try
    {
        var tryout = config.Get(typeof(AppSettings));
    }
    catch (Exception ex)
    {

        throw ex;
    }
}

tryout variable has the ApplicationName filled with value foo but the MyValues is just an empty array.

I also tried using object[] instead of List<object> and at that point it recognizes the amount of objects but all of the elements have the value null .

I don't want the MyValues array to be pre-defined because every element can and will have different fields and I want to make this process as generic as possible. How can I achieve this?

So, I found a way of achieving my goal, just not that straightforward but still pretty simple:

First I had to change my appsettings.Development.json file like this:

{
    "AppSettings":{
        "ApplicationName":"FOO"
        "MyValues":[
            "Tryout1": {
                "Name":"Tryout1",
                "QuestionCount": 7
            },
            "Tryout2": {
                "Name":"Tryout2"
                "SettingName":"ABCDEFG"
            }
        ]
    }
}

After this change, another change in the generic type is necessary, as follows:

public class AppSettings
{
    public string ApplicationName {get;set;}
    public Dictionary<string, CustomBaseClass> MyValues {get;set;}
    public List<object> _MyValues {get;set;}
}

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

public class Tryout1 : CustomBaseClass
{
    public int QuestionCount {get;set;}
}

public class Tryout2 : CustomBaseClass
{
    public string SettingName {get;set;}
}

This base class is important because we can't really bind the appsettings to an object, we still need a class. And base class, helps us bind these custom values like this:

private static List<Type> CustomTypes = new List<Type> { typeof(Tryout1), typeof(Tryout2) };

static ConfigurationHelper()
{
    var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
    
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile($"appsettings.{environmentName}.json")
        .Build();

    try
    {
        AppSettings = config.Get<AppSettingsContainer>();

        foreach (var keyValuePair in AppSettings.MyValues)
        {
            var type = CustomTypes.Where(t => t.Name == keyValuePair.Key).FirstOrDefault();

            if (type != null)
            {
                var myValue = config.GetSection(string.Format("AppSettings:MyValues:{0}", keyValuePair.Key)).Get(type);

                if (job != null)
                {
                    AppSettings._MyValues.Add(myValue);
                }
            }
        }
    }
    catch (Exception ex)
    {

        throw ex;
    }
}

This should solve this problem, and huge thanks to andrewlock.net because I got the inital Dictionary<string, T> idea from there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM