C# 无法从Json序列化IConfigurationSection

C# 无法从Json序列化IConfigurationSection,c#,json.net,C#,Json.net,我有以下基于Json的配置文件: { "PostProcessing": { "ValidationHandlerConfiguration": { "MinimumTrustLevel": 80, "MinimumMatchingTrustLevel": 75 }, "MatchingCharacterRemovals": [ "-", "''", ":" ] }, "Processing"

我有以下基于Json的配置文件:

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