C# 无法从Json序列化IConfigurationSection
我有以下基于Json的配置文件:C# 无法从Json序列化IConfigurationSection,c#,json.net,C#,Json.net,我有以下基于Json的配置文件: { "PostProcessing": { "ValidationHandlerConfiguration": { "MinimumTrustLevel": 80, "MinimumMatchingTrustLevel": 75 }, "MatchingCharacterRemovals": [ "-", "''", ":" ] }, "Processing"
{
"PostProcessing": {
"ValidationHandlerConfiguration": {
"MinimumTrustLevel": 80,
"MinimumMatchingTrustLevel": 75
},
"MatchingCharacterRemovals": [
"-",
"''",
":"
]
},
"Processing": {
"OrderSelection": {
"SelectionDaysInterval": 30,
"SelectionDaysMaximum": 365
}
}
}
作为序列化框架,我使用Newtonsoft。为了将此配置序列化为对象,我实现了以下类:
[JsonObject(MemberSerialization.OptIn)]
public class RecognitionConfiguration {
[JsonProperty(PropertyName = "PostProcessing", Required = Required.Always)]
public PostRecognitionConfiguration PostRecognitionConfiguration { get; set; }
[JsonProperty(PropertyName = "Processing", Required = Required.Always)]
public ProcessRecognitionConfiguration ProcessRecognitionConfiguration { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public class PostRecognitionConfiguration {
[JsonProperty(Required = Required.Always)]
public ValidationHandlerConfiguration ValidationHandlerConfiguration { get; set; }
[JsonProperty] public List<string> MatchingCharacterRemovals { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public class ProcessRecognitionConfiguration {
[JsonProperty(PropertyName = "OrderSelection", Required = Required.Always)]
public OrderSelectionConfiguration OrderSelectionConfiguration { get; set; }
}
很好用。你知道为什么在JsonProperty上设置PropertyName似乎没有任何效果吗?这是故意的。通过配置绑定到POCO是按照约定完成的。与绑定到控制器动作参数的模型不同 它将POCO上的属性名称与提供的JSON中的键相匹配 参考文献 因此,要么更改设置以匹配原始问题中显示的类,要么更改类以匹配基于Json的配置文件中的设置键
[JsonObject(MemberSerialization.OptIn)]
public class RecognitionConfiguration {
[JsonProperty(PropertyName = "PostProcessing", Required = Required.Always)]
public PostRecognitionConfiguration PostProcessing{ get; set; }
[JsonProperty(PropertyName = "Processing", Required = Required.Always)]
public ProcessRecognitionConfiguration Processing{ get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public class PostRecognitionConfiguration {
[JsonProperty(Required = Required.Always)]
public ValidationHandlerConfiguration ValidationHandlerConfiguration { get; set; }
[JsonProperty]
public List<string> MatchingCharacterRemovals { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
public class ProcessRecognitionConfiguration {
[JsonProperty(PropertyName = "OrderSelection", Required = Required.Always)]
public OrderSelectionConfiguration OrderSelection { get; set; }
}
public partial class ValidationHandlerConfiguration {
[JsonProperty("MinimumTrustLevel")]
public long MinimumTrustLevel { get; set; }
[JsonProperty("MinimumMatchingTrustLevel")]
public long MinimumMatchingTrustLevel { get; set; }
}
public partial class OrderSelectionConfiguration {
[JsonProperty("SelectionDaysInterval")]
public long SelectionDaysInterval { get; set; }
[JsonProperty("SelectionDaysMaximum")]
public long SelectionDaysMaximum { get; set; }
}
[JsonObject(MemberSerialization.OptIn)]
公共类识别配置{
[JsonProperty(PropertyName=“PostProcessing”,Required=Required.Always)]
公共后识别配置后处理{get;set;}
[JsonProperty(PropertyName=“Processing”,Required=Required.Always)]
公共进程识别配置处理{get;set;}
}
[JsonObject(MemberSerialization.OptIn)]
公共类后识别配置{
[JsonProperty(必需=必需。始终)]
公共验证HandlerConfiguration验证HandlerConfiguration{get;set;}
[JsonProperty]
公共列表匹配CharacterRemovals{get;set;}
}
[JsonObject(MemberSerialization.OptIn)]
公共类ProcessRecognitionConfiguration{
[JsonProperty(PropertyName=“OrderSelection”,Required=Required.Always)]
public OrderSelectionConfiguration OrderSelection{get;set;}
}
公共部分类ValidationHandlerConfiguration{
[JsonProperty(“MinimumTrustLevel”)]
公共长最小信任级别{get;set;}
[JsonProperty(“MinimumMatchingTrustLevel”)]
公共长最小匹配信任级别{get;set;}
}
公共部分类OrderSelectionConfiguration{
[JsonProperty(“SelectionDaysInterval”)]
public long SelectionDaysInterval{get;set;}
[JsonProperty(“SelectionDaysMaximum”)]
public long selectiondaysmax{get;set;}
}
在JsonProperty
上更改PropertyName
确实有效。这是我尝试过的同样的方法,它确实对我有效:
我的JSON数据:
{"name": "John","age": 30,"cars": [ "Ford", "BMW", "Fiat" ]}
模型:
public class RootObject
{
[JsonProperty(PropertyName ="name")]
public string Apple { get; set; }
public int age { get; set; }
public List<string> cars { get; set; }
}
公共类根对象
{
[JsonProperty(PropertyName=“name”)]
公共字符串Apple{get;set;}
公共整数{get;set;}
公共列表车辆{get;set;}
}
代码如下:
RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);
rootobjectobj=JsonConvert.DeserializeObject(json);
这是我得到的输出
您需要将JsonProperty
中的PropertyName
设置为与json文件属性名称相同,但是您的C#model属性可以是您想要的,只是它们需要用[JsonProperty(PropertyName=“jsonPropertyName”)]
装饰,希望这能帮助您解决问题
愉快的编码…编辑:我发现这一个比我以前的解决方案更令人愉快:在ExpandoObject
中绑定所有内容,将它们写入JSON并使用JSON.NET将它们绑定回来:
以下是我的测试MySettings
课程:
public class MySettings
{
[JsonProperty("PostProcessing")]
public SomeNameElseSettings SomenameElse { get; set; }
public class SomeNameElseSettings
{
[JsonProperty("ValidationHandlerConfiguration")]
public ValidationHandlerConfigurationSettings WhateverNameYouWant { get; set; }
public class ValidationHandlerConfigurationSettings
{
[JsonProperty("MinimumTrustLevel")]
public int MinimumTrustLevelFoo { get; set; }
[JsonProperty("MinimumMatchingTrustLevel")]
public int MinimumMatchingTrustLevelBar { get; set; }
}
}
}
通话结束后,我得到了您想要的一切:
旧答案:
根据你的观点,做你所需要的事情几乎是不可能的。我已经尝试了JsonProperty
和DataContract
,但Binder都不认可这两种方法,因为源代码本身只使用属性名
如果您仍然坚持,有两种可能性,但我不推荐任何可能性,因为更改属性名称要简单得多:
- 将源代码放到那里,或者简单地复制该文件(在我尝试跟踪代码时,我将所有方法重命名为
Bind2
,BindInstance2
等),并相应地重写代码
- 这一个非常特定于当前实现,因此它不是未来的证明:当前代码正在调用
config.GetSection(property.Name)
,因此,您可以编写自己的IConfiguration
,为GetSection
方法提供自己的名称,并将其点击到引导过程中,而不是使用默认方法
当您调试并调用var serializedConfiguration=this.ConfigurationSection.Get()时代码>在尝试注册子对象之前,对象中是否存在该时间点的值?@KieranDevlin我编辑了我的帖子以向您展示。编辑您的并从中删除Autofac。感兴趣的部分是ConfigurationSection.Get()
,以及应该反序列化的json。属性为null
这一事实与Autofac无关,将此问题留在您的问题中只会增加噪音。@Igor感谢您的反馈。我已经重构了我的帖子。@rbr94这是出于设计。通过配置绑定到POCO不像模型绑定到动作参数。它将POCO上的属性名称与提供的JSON中的键相匹配。读到这里谢谢你的回答。这真的很有帮助!我希望有一个解决方案,可以像在NewtonSoft中那样指定自定义属性名。虽然我的答案可以解决OP的问题,但我认为(目前)任何情况都不需要涉及复杂性。如果可能的话,我强烈推荐使用这个。关于这个问题。。。[JsonProperty]和[JsonObject]属性现在变得毫无意义了?我认为这与我的问题无关。使用Newtonsoft进行反序列化没有问题,但是使用iconfiguration部分的Get
扩展
public class RootObject
{
[JsonProperty(PropertyName ="name")]
public string Apple { get; set; }
public int age { get; set; }
public List<string> cars { get; set; }
}
RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);
namespace Microsoft.Extensions.Configuration
{
public static class ConfigurationBinder
{
public static void BindJsonNet(this IConfiguration config, object instance)
{
var obj = BindToExpandoObject(config);
var jsonText = JsonConvert.SerializeObject(obj);
JsonConvert.PopulateObject(jsonText, instance);
}
private static ExpandoObject BindToExpandoObject(IConfiguration config)
{
var result = new ExpandoObject();
// retrieve all keys from your settings
var configs = config.AsEnumerable();
foreach (var kvp in configs)
{
var parent = result as IDictionary<string, object>;
var path = kvp.Key.Split(':');
// create or retrieve the hierarchy (keep last path item for later)
var i = 0;
for (i = 0; i < path.Length - 1; i++)
{
if (!parent.ContainsKey(path[i]))
{
parent.Add(path[i], new ExpandoObject());
}
parent = parent[path[i]] as IDictionary<string, object>;
}
if (kvp.Value == null)
continue;
// add the value to the parent
// note: in case of an array, key will be an integer and will be dealt with later
var key = path[i];
parent.Add(key, kvp.Value);
}
// at this stage, all arrays are seen as dictionaries with integer keys
ReplaceWithArray(null, null, result);
return result;
}
private static void ReplaceWithArray(ExpandoObject parent, string key, ExpandoObject input)
{
if (input == null)
return;
var dict = input as IDictionary<string, object>;
var keys = dict.Keys.ToArray();
// it's an array if all keys are integers
if (keys.All(k => int.TryParse(k, out var dummy)))
{
var array = new object[keys.Length];
foreach (var kvp in dict)
{
array[int.Parse(kvp.Key)] = kvp.Value;
}
var parentDict = parent as IDictionary<string, object>;
parentDict.Remove(key);
parentDict.Add(key, array);
}
else
{
foreach (var childKey in dict.Keys.ToList())
{
ReplaceWithArray(input, childKey, dict[childKey] as ExpandoObject);
}
}
}
}
}
var settings = new MySettings();
this.Configuration.BindJsonNet(settings);
public class MySettings
{
[JsonProperty("PostProcessing")]
public SomeNameElseSettings SomenameElse { get; set; }
public class SomeNameElseSettings
{
[JsonProperty("ValidationHandlerConfiguration")]
public ValidationHandlerConfigurationSettings WhateverNameYouWant { get; set; }
public class ValidationHandlerConfigurationSettings
{
[JsonProperty("MinimumTrustLevel")]
public int MinimumTrustLevelFoo { get; set; }
[JsonProperty("MinimumMatchingTrustLevel")]
public int MinimumMatchingTrustLevelBar { get; set; }
}
}
}