How to load polymorphic objects in appsettings.json How to load polymorphic objects in appsettings.json json json

How to load polymorphic objects in appsettings.json


The key to answer this question is to know how the keys are generated. In your case, the key / value pairs will be:

DynamicConfig:Features:0:TypeDynamicConfig:Features:0:Options:MaxFileSizeDynamicConfig:Features:1:TypeDynamicConfig:Features:1:Options:MinAgeDynamicConfig:Features:1:Options:MaxAgeDynamicConfig:Features:2:TypeDynamicConfig:Features:2:Options:MinAgeDynamicConfig:Features:2:Options:MaxAge

Notice how each element of the array is represented by DynamicConfig:Features:{i}.

The second thing to know is that you can map any section of a configuration to an object instance, with the ConfigurationBinder.Bind method:

var conf = new PersonCheckerOption();Configuration.GetSection($"DynamicConfig:Features:1:Options").Bind(conf);

When we put all this together, we can map your configuration to your data structure:

services.Configure<FeaturesOptions>(opts =>{    var features = new List<FeatureConfig>();    for (var i = 0; ; i++)    {        // read the section of the nth item of the array        var root = $"DynamicConfig:Features:{i}";        // null value = the item doesn't exist in the array => exit loop        var typeName = Configuration.GetValue<string>($"{root}:Type");        if (typeName == null)            break;        // instantiate the appropriate FeatureConfig         FeatureConfig conf = typeName switch        {            "FileSizeChecker" => new FileSizeCheckerOptions(),            "PersonChecker" => new PersonCheckerOption(),            _ => throw new InvalidOperationException($"Unknown feature type {typeName}"),        };        // bind the config to the instance        Configuration.GetSection($"{root}:Options").Bind(conf);        features.Add(conf);    }    opts.Features = features.ToArray();});

Note: all options must derive from FeatureConfig for this to work (e.g. public class FileSizeCheckerOptions : FeatureConfig). You could even use reflection to automatically detect all the options inheriting from FeatureConfig, to avoid the switch over the type name.

Note 2: you can also map your configuration to a Dictionary, or a dynamic object if you prefer; see my answer to Bind netcore IConfigurationSection to a dynamic object.