簡體   English   中英

如何在 appsettings.json 中加載多態對象

[英]How to load polymorphic objects in appsettings.json

有沒有辦法以強類型的方式從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
                }
            }
        ]
    }
}

啟動文件

    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;
    }

其他定義

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; }

}

回答這個問題的關鍵是要知道密鑰是如何生成的。 在您的情況下,鍵/值對將是:

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

請注意數組的每個元素如何由DynamicConfig:Features:{i}

要知道的第二件事是,您可以使用ConfigurationBinder.Bind方法將ConfigurationBinder.Bind任何部分映射到對象實例:

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

當我們將所有這些放在一起時,我們可以將您的配置映射到您的數據結構:

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();
});

注意:所有選項都必須派生自FeatureConfig才能工作(例如public class FileSizeCheckerOptions : FeatureConfig )。 您甚至可以使用反射來自動檢測從FeatureConfig繼承的所有選項,以避免切換類型名稱。

注 2:如果您願意,您還可以將配置映射到Dictionarydynamic對象; 請參閱我將netcore IConfigurationSection 綁定到動態對象的答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM