如何在 appsettings.json 中加载多态对象

Kar*_*ral 7 c# polymorphism json json-deserialization asp.net-core

有没有办法以appsettings.json强类型的方式读取多态对象?下面是我需要的一个非常简化的例子。

我有多个应用程序组件,Features在此处命名。这些组件由工厂在运行时创建。我的设计意图是每个组件都由其单独的强类型选项配置。在这个例子中,FileSizeCheckerOptionsPersonCheckerOption是这些的实例。每个功能都可以使用不同的选项多次包含。

但是使用现有的 ASP.NET Core 配置系统,我无法读取多态强类型选项。如果设置是由 JSON 反序列化器读取的,我可以使用类似这样的东西。但这不是appsettings.json,其中选项只是键值对。

appsettings.json

{
    "DynamicConfig":
    {
        "Features": [
            {
                "Type": "FileSizeChecker",
                "Options": { "MaxFileSize": 1000 }
            },
            {
                "Type": "PersonChecker",
                "Options": {
                    "MinAge": 10,
                    "MaxAge": 99
                }
            },
            {
                "Type": "PersonChecker",
                "Options": {
                    "MinAge": 15,
                    "MaxAge": 20
                }
            }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

启动文件

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<FeaturesOptions>(Configuration.GetSection("DynamicConfig"));
        ServiceProvider serviceProvider = services.BuildServiceProvider();
        // try to load settings in strongly typed way
        var options = serviceProvider.GetRequiredService<IOptions<FeaturesOptions>>().Value;
    }
Run Code Online (Sandbox Code Playgroud)

其他定义

public enum FeatureType
{
    FileSizeChecker,
    PersonChecker
}

public class FeaturesOptions
{
    public FeatureConfig[] Features { get; set; }
}

public class FeatureConfig
{
    public FeatureType Type { get; set; }
    // cannot read polymorphic object
    // public object Options { get; set; } 
}

public class FileSizeCheckerOptions
{
    public int MaxFileSize { get; set; }
}

public class PersonCheckerOption
{
    public int MinAge { get; set; }
    public int MaxAge { get; set; }

}
Run Code Online (Sandbox Code Playgroud)

Mét*_*ule 10

回答这个问题的关键是要知道密钥是如何生成的。在您的情况下,键/值对将是:

DynamicConfig:Features:0:Type
DynamicConfig:Features:0:Options:MaxFileSize
DynamicConfig:Features:1:Type
DynamicConfig:Features:1:Options:MinAge
DynamicConfig:Features:1:Options:MaxAge
DynamicConfig:Features:2:Type
DynamicConfig:Features:2:Options:MinAge
DynamicConfig:Features:2:Options:MaxAge
Run Code Online (Sandbox Code Playgroud)

请注意数组的每个元素是如何表示的DynamicConfig:Features:{i}

第二件事要知道的是,您可以使用以下方法将配置的任何部分映射到对象实例ConfigurationBinder.Bind

DynamicConfig:Features:0:Type
DynamicConfig:Features:0:Options:MaxFileSize
DynamicConfig:Features:1:Type
DynamicConfig:Features:1:Options:MinAge
DynamicConfig:Features:1:Options:MaxAge
DynamicConfig:Features:2:Type
DynamicConfig:Features:2:Options:MinAge
DynamicConfig:Features:2:Options:MaxAge
Run Code Online (Sandbox Code Playgroud)

当我们将所有这些放在一起时,我们可以将您的配置映射到您的数据结构:

var conf = new PersonCheckerOption();
Configuration.GetSection($"DynamicConfig:Features:1:Options").Bind(conf);
Run Code Online (Sandbox Code Playgroud)

注意:所有选项都必须派生FeatureConfig自此才能工作(例如public class FileSizeCheckerOptions : FeatureConfig)。您甚至可以使用反射来自动检测继承自 的所有选项FeatureConfig,以避免类型名称的切换。

注 2:如果您愿意,您还可以将配置映射到Dictionary, 或对象;请参阅我对将 netcore IConfigurationSection 绑定到动态对象的dynamic回答。