【问题标题】:How to serialize a JObject the same way as an object with Json.NET?如何以与使用 Json.NET 的对象相同的方式序列化 JObject?
【发布时间】:2016-10-25 15:49:49
【问题描述】:

如何控制 JObject 到字符串的序列化?

我有一些返回 JObject 的 API,我通常会应用一些更改并保留或返回它们。我想避免保留空属性并应用一些额外的格式,但 JsonConvert 似乎完全忽略了我的设置。

这是问题的示例:

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

发帖{ "Foo": "Foo", "Bar": null }:

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

我希望 JObject 方法返回与使用对象相同的输出 json。我如何在不创建助手的情况下实现这一目标?有没有办法使用相同的设置序列化 JObject?

【问题讨论】:

标签: c# json.net


【解决方案1】:

与 NewtonSoft 框架完美集成的解决方案是提供一个自定义 JObject 转换器,该转换器支持 NamingStrategy

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

用法

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

您可以在 GitHub 上找到有效的 PoC。

【讨论】:

  • 这似乎完美地回答了这个问题。刚刚在 .net Core 3 中实现了这个。但是,除了这个答案之外,如果它与所有 JObject 相关,您可以简单地在序列化程序设置转换器中的 NewtonsoftJson 设置的根级别添加转换器。 MvcNewtonsoftJsonOptions.SerializerSettings.Converters.Add
【解决方案2】:

我能够做到这一点的唯一方法是首先将JObject转换为string,然后将该字符串反序列化为ExpandoObject(不要反序列化为object,因为你会回来的JObject)。 ExpandoObject 就像一个字典,这将导致JsonConvert 实际调用配置的名称大小写策略。我不确定为什么 Newtonsoft.Json 的作者没有像处理字典类型那样处理 JObject 类型,但至少这种解决方法有效。

例子:

// 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"}

我在这里用ExpandoObject 找到了诀窍:JObject & CamelCase conversion with JSON.Net

【讨论】:

  • 投了赞成票,因为它帮助我解决了一个类似的问题,即序列化 JObject 输出不可用的数组而不是我们的 JSON 日志格式的值。因此,将任何 JObject 反序列化为 ExpandoObject 并进行序列化,这让我解决了我的问题。
【解决方案3】:

JObject 被序列化时,它的原始 JSON 被写入。 JsonSerializerSettings 不会影响其写入的 JSON。

【讨论】:

  • -1;这个答案对我没有任何意义。 JObject 的“原始 JSON”是什么? JObject 文档中没有使用该术语,并且没有明显的含义,特别是考虑到 JObject 可以包含 JTokens 之类的日期和 GUID,它们不属于 JSON 规范并且具有多种可能的序列化。
  • @MarkAmery 您知道 James 编写/维护 Json.NET,对吗? ;^DI 认为他只是在说 JObject 不被认为是一流的对象Json.NET 并且它会忽略您的序列化程序设置(也许认为,作为JObject,它已经被序列化了)。如果你想序列化你的JObject,你必须首先将它反序列化为一个真正的强类型。解释 OP 和我所看到的,并与 Sipke 和 Goo 的解决方案(和 dbc 的评论)相提并论。
  • @ruffin 是的,我知道 James 是项目的作者。毫无疑问,JObject 的“原始 JSON”的概念对 非常有意义,基于 Json.NET 代码库中使用的抽象,或者可能只是在 James 的头脑中。但这并不能改变对我们其他人来说基本上是无稽之谈的事实。
  • 虽然我很欣赏创作这个伟大库的努力,但这是一个非常突然的“答案”。无论这是否最近添加到 2016 年,都可以通过为 JObject 添加序列化器转换器以根据需要进行序列化来回答这个问题 - 请参阅其他答案 stackoverflow.com/a/51272107/110495
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-25
  • 2020-06-12
  • 1970-01-01
  • 1970-01-01
  • 2020-07-17
  • 1970-01-01
  • 2017-06-30
相关资源
最近更新 更多