[英]How to load polymorphic objects in appsettings.json
有沒有辦法以強類型的方式從appsettings.json
讀取多態對象? 下面是我需要的一個非常簡化的例子。
我有多個應用程序組件,在此處命名為Features
。 這些組件由工廠在運行時創建。 我的設計意圖是每個組件都由其單獨的強類型選項配置。 在這個例子中FileSizeCheckerOptions
和PersonCheckerOption
是這些的實例。 每個功能都可以使用不同的選項多次包含。
但是使用現有的 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:如果您願意,您還可以將配置映射到Dictionary
或dynamic
對象; 請參閱我將netcore IConfigurationSection 綁定到動態對象的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.