当JSON.NET序列化类型时,我想在json输出中为特定类型的实例引入一些元数据属性。
在保留序列化上下文和设置的同时引入这些附加属性的最佳方法是什么?
我知道我可以实现JsonConverter
并将其添加到序列化设置中。以下是WriteJson
的示例实现:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var Json = JObject.FromObject(value, serializer);
//modify Json by adding some properties ...
Json.WriteTo(writer);
}
然而,这提出了一些我不确定如何解决的问题:
如果通过设置配置序列化器:
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
然后尝试调用JObject.FromObject(value, serializer)
没有任何序列化,因为JSON.NET已经确定该值被序列化(因此它忽略了序列化相同引用的进一步尝试)。
如果我设置ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize
,那么我最终会得到一个无限递归循环。致电JObject.FromObject(value, serializer)
最终会重新输入自定义WriteJson
的{{1}}。
如果我创建了一个新的序列化程序,或者调用JsonConverter
(如this example所示),我将不再使用相同的序列化程序设置。虽然输出将具有额外的属性,但如果已为原始序列化器配置了其他转换器,合同解析器等,则它可能与序列化json的其余部分不匹配。另外,我已经丢失了参考循环处理的序列化上下文,因此将不再跳过原始输出中跳过的引用。
有没有更好的方法可以挂钩序列化过程,允许您修改原始序列化程序生成的json?
更新:目前我已经实施了一个不太理想的解决方法,即为我的自定义JObject.FromObject(value)
提供设置工厂Func<JsonSerializerSettings>
。提供的设置必须排除转换器以避免递归循环,这不会保留序列化上下文。此外,由于不再配置转换器,因此任何嵌套对象都不会接收其他属性。
答案 0 :(得分:6)
我发现我可以实现自定义IContractResolver
并覆盖CreateProperties
以包含任意数量的其他属性以及提供实际属性值的IValueProvider
。
此方法不是编写JsonConverter
来序列化对象然后添加属性,而是修改特定类型的合同,然后由序列化程序使用。
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var Result = base.CreateProperties(type, memberSerialization);
//check if this is a type we add properties to
if (IsAnnotatedType(type))
{
Result.Add(new JsonProperty
{
PropertyType = typeof(string),
PropertyName = "AdditionalProperty",
Readable = true,
Writable = false,
//value provider will receive the object instance when GetValue is called
ValueProvider = new AdditionalPropertyValueProvider()
});
}
return Result;
}