我有以下基于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 似乎没有效果?
答案 0 :(得分:2)
那是设计使然。通过配置绑定到POCO是按照惯例完成的。不像模型绑定到Controller Action参数。
它将POCO上的属性名称与提供的JSON中的键匹配。
引用Configuration in 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; }
}
答案 1 :(得分:1)
编辑:我发现这个解决方案比以前的解决方案要愉快得多:将所有内容绑定到ExpandoObject
中,将它们写入JSON并使用JSON.NET将其绑定回去。 Using the code of this article:
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; }
}
}
}
打完电话,我随心所欲:
旧答案:
根据source code here,根本(几乎)不可能做您需要的事情。我已经尝试过JsonProperty
和DataContract
,但都没有受到活页夹的认可,仅仅是因为源代码本身只是使用属性名。
如果您仍然坚持,则有两种可能性,但是我不建议任何一种,因为更改属性的名称要简单得多:
在此处分叉您的源代码,或简单地复制该文件(在我试图跟踪代码的过程中,我将所有方法重命名为Bind2
,BindInstance2
等),然后重写相应的代码。
此代码非常特定于当前实现,因此不符合未来发展趋势:当前代码正在调用config.GetSection(property.Name)
,因此您可以编写自己的IConfiguration
并为其提供名称GetSection
方法,然后将其点击进入引导过程,而不使用默认方法。
答案 2 :(得分:-1)
将PropertyName
更改为JsonProperty
确实有效。这是我尝试过的方法,对我确实有用:
我的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);
这是我得到的输出
您需要在PropertyName
中将JsonProperty
设置为与json文件属性名称相同,但是您的C#模型属性可以是您想要的,只是它们需要用[JsonProperty(PropertyName ="jsonPropertyName")]
装饰这可以帮助您解决问题。
快乐的编码...