簡體   English   中英

無法從Json序列化IConfigurationSection

[英]Fail to serialize IConfigurationSection from Json

我有以下基於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; }
}

在類中,我嘗試使用IConfigurationSection.Get()將特定配置節序列化為這些類結構。

var serializedConfiguration = this.ConfigurationSection.Get<RecognitionConfiguration>();

但是當我調試代碼時,我總是得到一個“空”變量serializedConfiguration ,它不是null,但是所有屬性都是null。

在此輸入圖像描述

如果我使用

this.ConfigurationSection.GetSection("Processing").Get<ProcessRecognitionConfiguration>()

或者更改json文件中屬性的命名,使其與類中的屬性名稱完全匹配,如下所示:

{   
  "ProcessRecognitionConfiguration": {
    "OrderSelectionConfiguration": {
      "SelectionDaysInterval": 30,
      "SelectionDaysMaximum": 365
    }
  }
}

它工作正常。 你有什么想法,為什么在JsonProperty上設置PropertyName似乎沒有任何影響?

那是設計上的。 通過配置綁定到POCO是按照慣例完成的。 不像模型綁定到控制器動作參數。

它將POCO上的屬性名稱與提供的JSON中的鍵進行匹配。

ASP.NET Core中的參考配置

因此,要么更改設置以匹配原始問題中顯示的類,要么更改類以匹配基於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; }
}

編輯:我發現這個比以前的解決方案更令人愉快:將所有內容綁定到ExpandoObject ,將它們寫入JSON並使用JSON.NET將它們綁定回來。 使用本文的代碼

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

這是我的測試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; }
        }
    }
}

通話結束后,我按照你的意願得到了一切:

在此輸入圖像描述


舊答案:

根據這里源代碼 ,只需(幾乎)不可能完成您的要求。 我已經嘗試了JsonPropertyDataContract ,其中沒有一個被Binder尊重,只是因為源代碼本身只使用屬性名稱。

如果您仍然堅持,有兩種可能性,但我不建議任何更改屬性的名稱更簡單:

  • 在那里分叉您的源代碼,或者只是復制該文件(在我嘗試跟蹤代碼時,我將所有方法重命名為類似Bind2BindInstance2等),並相應地重寫代碼。

  • 這個是非常具體的當前實現,因此它不是面向未來的:當前代碼調用config.GetSection(property.Name) ,因此您可以編寫自己的IConfiguration並為GetSection方法提供自己的名稱並將其點擊到引導過程而不是使用默認過程。

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

這是代碼:

RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);

這是我得到的輸出

在此輸入圖像描述

您需要在JsonProperty設置PropertyName與json文件屬性名稱相同,但您的C#模型屬性可以是您想要的,只需要用[JsonProperty(PropertyName ="jsonPropertyName")]希望這有助於您解決問題。

快樂的編碼......

暫無
暫無

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

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