当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);
}
Run Code Online (Sandbox Code Playgroud)
但是,这提出了一些我不确定如何解决的问题:
如果通过设置配置序列化程序:
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
然后尝试调用JObject.FromObject(value, serializer)序列化什么,因为JSON.NET已经确定该值被序列化(因此它忽略了序列化相同引用的进一步尝试).
如果我设置ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize然后我最终得到一个无限递归循环.呼叫JObject.FromObject(value, serializer)最终重新进入WriteJson我的自定义JsonConverter.
如果我创建一个新的序列化器或调用JObject.FromObject(value)(如本例所示),我将不再使用相同的序列化器设置.虽然输出将具有额外的属性,但如果已为原始序列化器配置了其他转换器,合同解析器等,则它可能与序列化json的其余部分不匹配.另外,我已经丢失了参考循环处理的序列化上下文,因此将不再跳过原始输出中将跳过的引用.
是否有更好的方法可以挂钩序列化过程,允许您修改原始序列化程序生成的json?
更新:目前我实现了一个不太理想的解决方法,即为Func<JsonSerializerSettings>我的自定义提供设置工厂JsonConverter.提供的设置必须排除转换器以避免递归循环,这不会保留序列化上下文.此外,由于不再配置转换器,因此任何嵌套对象都不会接收其他属性.
我发现我可以实现自定义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;
}
Run Code Online (Sandbox Code Playgroud)