C# 如何以与Json.NET对象相同的方式序列化JObject?
如何控制JObject到字符串的序列化 我有一些返回JObject的API,我通常会应用一些更改并保存或返回它们。我希望避免保留空属性并应用一些额外的格式,但JsonConvert似乎完全忽略了我的设置 以下是问题的示例:C# 如何以与Json.NET对象相同的方式序列化JObject?,c#,json.net,C#,Json.net,如何控制JObject到字符串的序列化 我有一些返回JObject的API,我通常会应用一些更改并保存或返回它们。我希望避免保留空属性并应用一些额外的格式,但JsonConvert似乎完全忽略了我的设置 以下是问题的示例: // startup.cs has the following services.AddMvc().AddJsonOptions(o => { o.SerializerSettings.NullValueHandling = NullValueHandling.
// 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?当序列化
JObject
时,会写入原始JSONJsonSerializerSettings
不会影响其编写的JSON。我能够做到这一点的唯一方法是首先将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"}
//构造一个作业对象。
var jObject=jObject.Parse(“{SomeName:\“Some value\”}”);
//将对象反序列化为ExpandooObject(不要使用object,因为这样会得到一个JobObject)。
var payload=JsonConvert.DeserializeObject(jObject.ToString());
//现在,您可以使用喜欢的任何序列化程序设置序列化对象。
var json=JsonConvert.SerializeObject(有效负载,新的JsonSerializerSettings
{
ContractResolver=新的DefaultContractResolver
{
NamingStrategy=新CamelCaseNamingStrategy
{
//重要提示!请确保将其设置为true,因为ExpandoObject就像一本字典。
ProcessDictionaryKeys=true,
}
}
}
);
Console.WriteLine(json);//输出:{“someName”:“somevalue”}
我在这里学习了
ExpandoObject
的技巧:与NewtonSoft框架很好地集成的一个解决方案是提供一个定制的JObject转换器,它尊重NamingStrategy
JObject自定义转换器
您可以在上找到一个正在工作的PoC。难道
JObject
没有返回JSON的ToString
方法吗?我认为在使用JsonConvert.SerializObject()进行序列化期间,您不能“编辑”一个JObject
。一个JObject
已经被序列化,所以所有jsonvert
所做的都是或多或少地逐字发送它。看见有关解决方法,请参见@MikeMcCaughan JObject.ToString将对象转换为json,但没有任何重载来接受设置对象;这个答案对我来说没有任何意义。作业对象的“原始JSON”是什么?这个术语在JObject
文档中没有使用,也没有明显的含义,特别是考虑到JObject
可以包含JToken
之类的日期和GUID,它们不属于JSON规范,并且有多个可能的序列化。@MarkAmery您知道James编写/维护了JSON.NET,对吗^D我想他只是说,Json.NET并不认为JObject
是一级对象,它会忽略您的序列化程序设置(可能考虑到作为JObject
,它已经被序列化了)。如果要序列化作业对象
,必须首先将其反序列化为真正的强类型。解释OP和我所看到的,并与Sipke和Goo的解决方案(和dbc的评论)相一致。@ruffin是的,我意识到James是项目作者。毫无疑问,JObject
的“原始JSON”的概念对他来说是非常有意义的,基于JSON.NET代码库中使用的抽象,或者可能就在James的头脑中。但这并不能改变这样一个事实:对我们其他人来说,这基本上是胡说八道。虽然我很欣赏创作这本伟大的自传的努力,但这是一个非常突然的“答案”。无论这是不是最近添加到2016年,这个问题都可以通过为JObject添加一个序列化器转换器来回答,以便根据需要进行序列化-参见其他答案这似乎完美地回答了这个问题。刚刚在.NETCore3中实现了这个。但是,对于这个答案,如果它与所有JObject相关,您只需在序列化程序设置转换器中的NewtonsoftJson设置的根级别添加转换器<代码>MvcNewtonsoftJsonOptions.SerializerSettings.Converters.Add
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);