简体   繁体   English

如何使用Json.NET以与对象相同的方式序列化JObject?

[英]How to serialize a JObject the same way as an object with Json.NET?

How do I control the serialization of a JObject to string? 如何控制JObject到字符串的序列化?

I have some APIs that return a JObject and I usually apply some changes and persist or return them. 我有一些返回JObject的API,我通常会应用一些更改并保留或返回它们。 I want to avoid persisting null properties and apply some additional formatting, but JsonConvert seems to completely ignore my settings. 我想避免持久化null属性并应用一些额外的格式,但JsonConvert似乎完全忽略我的设置。

Here is the sample of the problem: 以下是问题的示例:

// startup.cs has the following
services.AddMvc().AddJsonOptions(o =>
{
    o.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});

public class SampleController : Controller
{
    JsonSerializerSettings _settings = new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    };

    [HttpPost]
    [Route("object")]
    public object PostObject([FromBody] SomeObject data)
    {
        return JsonConvert.SerializeObject(data, _settings);
    }

    [HttpPost]
    [Route("jobject")]
    public object PostJObject([FromBody] JObject data)
    {
        return JsonConvert.SerializeObject(data, _settings);
    }

    public class SomeObject
    {
        public string Foo { get; set; }
        public string Bar { get; set; }
    }
}

Posting { "Foo": "Foo", "Bar": null } : 发布{ "Foo": "Foo", "Bar": null }

  • /object returns {"Foo":"Foo"} /object返回{"Foo":"Foo"}
  • /jobject returns {"Foo":"Foo","Bar":null} /jobject返回{"Foo":"Foo","Bar":null}

I want the JObject method to return the same output json as if I were using an object. 我希望JObject方法返回相同的输出json,就像我使用对象一样。 How do I achieve this without creating helpers? 如何在不创建助手的情况下实现这一目标? Is there a way to serialize the JObject using the same settings? 有没有办法使用相同的设置序列化JObject?

The only way I was able to do this is by first converting the JObject to a string , then deserializing that string into an ExpandoObject (don't deserialize to object because you'll get back a JObject ). 我能够做到这一点的唯一方法是首先将JObject转换为string ,然后将该字符串反序列化为ExpandoObject (不要反序列化为object因为你将返回一个JObject )。 The ExpandoObject is like a dictionary, which will cause JsonConvert to actually invoke the configured name case strategy. ExpandoObject就像一个字典,它将使JsonConvert实际调用配置的名称案例策略。 I'm not sure why the author of Newtonsoft.Json didn't handle JObject types the same way as they seem to be doing for dictionary types, but at least this work around works. 我不确定为什么Newtonsoft.Json的作者没有像他们为字典类型那样处理JObject类型,但至少这项工作是有效的。

Example: 例:

// Construct a JObject.
var jObject = JObject.Parse("{ SomeName: \"Some value\" }");

// Deserialize the object into an ExpandoObject (don't use object, because you will get a JObject).
var payload = JsonConvert.DeserializeObject<ExpandoObject>(jObject.ToString());

// Now you can serialize the object using any serializer settings you like.
var json = JsonConvert.SerializeObject(payload, new JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver
    {
        NamingStrategy = new CamelCaseNamingStrategy
        {
            // Important! Make sure to set this to true, since an ExpandoObject is like a dictionary.
            ProcessDictionaryKeys = true,
        }
    }
}
);

Console.WriteLine(json); // Outputs: {"someName":"Some value"}

I picked-up the trick with the ExpandoObject here: JObject & CamelCase conversion with JSON.Net 我在这里使用ExpandoObject获取技巧:使用JSON.Net进行JObject和CamelCase转换

A solution that well integrates with NewtonSoft framework is to provide a custom JObject converter that honours the NamingStrategy . 与NewtonSoft框架完美集成的解决方案是提供一个尊重NamingStrategy的自定义JObject转换器。

JObject Custom Converter JObject定制转换器

public class JObjectNamingStrategyConverter : JsonConverter<JObject> {

private NamingStrategy NamingStrategy { get; }

public JObjectNamingStrategyConverter (NamingStrategy strategy) {
    if (strategy == null) {
        throw new ArgumentNullException (nameof (strategy));
    }
    NamingStrategy = strategy;
}

public override void WriteJson (JsonWriter writer, JObject value, JsonSerializer serializer) {
    writer.WriteStartObject ();
    foreach (JProperty property in value.Properties ()) {
        var name = NamingStrategy.GetPropertyName (property.Name, false);
        writer.WritePropertyName (name);
        serializer.Serialize (writer, property.Value);
    }
    writer.WriteEndObject ();
}

public override JObject ReadJson (JsonReader reader, Type objectType, JObject existingValue, bool hasExistingValue, JsonSerializer serializer) {
    throw new NotImplementedException ();
}
}

Usage 用法

var snakeNameStrategy = new SnakeCaseNamingStrategy ();
var jsonSnakeSettings = new JsonSerializerSettings {
Formatting = Formatting.Indented,
Converters = new [] { new JObjectNamingStrategyConverter (snakeNameStrategy) },
   ContractResolver = new DefaultContractResolver {
       NamingStrategy = snakeNameStrategy
   },
};

var json = JsonConvert.SerializeObject (obj, jsonSnakeSettings);

You can find a working PoC on GitHub . 你可以在GitHub上找到一个正常工作的PoC。

When a JObject is serialized its raw JSON is written. 当一个JObject被序列化时,它的原始JSON被写入。 JsonSerializerSettings do not effect its written JSON. JsonSerializerSettings不影响其编写的JSON。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM