如何在 appsettings.json 中加载多态对象
Posted
技术标签:
【中文标题】如何在 appsettings.json 中加载多态对象【英文标题】:How to load polymorphic objects in appsettings.json 【发布时间】:2019-09-21 02:49:44 【问题描述】:有什么方法可以以强类型的方式从appsettings.json
读取多态对象?下面是我需要的一个非常简化的示例。
我有多个应用组件,在此处命名为 Features
。这些组件由工厂在运行时创建。我的设计意图是每个组件都由其单独的强类型选项配置。在此示例中,FileSizeCheckerOptions
和 PersonCheckerOption
是这些的实例。每个功能都可以通过不同的选项多次包含。
但是使用现有的 ASP.NET Core 配置系统,我无法读取 多态 强类型选项。如果设置是由 JSON 反序列化器读取的,我可以使用 something like this。但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
]
Startup.cs
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;
【问题讨论】:
只做"FileSizeCheckerOptions": "MaxFileSize": 1000
会有缺点吗?
@ScottHannen 它不会。我需要读取一种特性(FileSizeChecker
)——这是工厂创建新特性的关键。我需要为此功能加载选项。
您找到解决方案了吗?
@HariPachuveetil 我认为没有简单的解决方案。这是由 .Core 加载机制引起的,其中所有值都被视为键值对,因此没有多态空间。
【参考方案1】:
回答这个问题的关键是要知道密钥是如何生成的。在您的情况下,键/值对将是:
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
方法将配置的任何部分映射到对象实例:
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
对象;看我对Bind netcore IConfigurationSection to a dynamic object的回答。
【讨论】:
一个不费吹灰之力的问题的绝佳答案。以上是关于如何在 appsettings.json 中加载多态对象的主要内容,如果未能解决你的问题,请参考以下文章
关于ef core 将实体类生成到类库 , 将appsettings.json生成到debug目录下
如何在 .NET Core MVC 项目中转换 appsettings.json?
如何在 appSettings.json 中硬编码和读取字符串数组?