你的基本问题是你正在提供一个custom JsonConverter https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm对于您还想启用的类型PreserveReferencesHandling https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_PreserveReferencesHandling.htm。但每当应用自定义转换器时,它必须注意一切手动,包括解析和生成"$ref"
and "$id"
特性。您的转换器不会执行此操作,因此您的反序列化代码无法正确反序列化您的对象图。
The 接受的答案 https://stackoverflow.com/a/53716866/3744182 to 自定义对象序列化与 PreserveReferencesHandling https://stackoverflow.com/q/53695270/3744182包括一个模板转换器,显示如何处理这些属性。但是,由于您的转换器似乎只是在(反)序列化之前切换一些序列化器设置,因此您可以简单地调用以递归(反)序列化对象,在持续时间内禁用转换器,如下所示:
public class CustomJsonConverter : Newtonsoft.Json.JsonConverter
{
[ThreadStatic]
static bool disabled;
// Disables the converter in a thread-safe manner.
bool Disabled { get { return disabled; } set { disabled = value; } }
public override bool CanWrite { get { return !Disabled; } }
public override bool CanRead { get { return !Disabled; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
using (new PushValue<bool>(true, () => Disabled, val => Disabled = val))
using (new PushValue<PreserveReferencesHandling>(PreserveReferencesHandling.Objects, () => serializer.PreserveReferencesHandling, val => serializer.PreserveReferencesHandling = val))
using (new PushValue<DefaultValueHandling>(DefaultValueHandling.Ignore, () => serializer.DefaultValueHandling, val => serializer.DefaultValueHandling = val))
using (new PushValue<NullValueHandling>(NullValueHandling.Ignore, () => serializer.NullValueHandling, val => serializer.NullValueHandling = val))
{
serializer.Serialize(writer, value);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
using (new PushValue<bool>(true, () => Disabled, val => Disabled = val))
using (new PushValue<PreserveReferencesHandling>(PreserveReferencesHandling.Objects, () => serializer.PreserveReferencesHandling, val => serializer.PreserveReferencesHandling = val))
using (new PushValue<DefaultValueHandling>(DefaultValueHandling.Ignore, () => serializer.DefaultValueHandling, val => serializer.DefaultValueHandling = val))
using (new PushValue<NullValueHandling>(NullValueHandling.Ignore, () => serializer.NullValueHandling, val => serializer.NullValueHandling = val))
{
return serializer.Deserialize(reader, objectType);
}
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
public struct PushValue<T> : IDisposable
{
Action<T> setValue;
T oldValue;
public PushValue(T value, Func<T> getValue, Action<T> setValue)
{
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
setValue(value);
}
// By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
public void Dispose()
{
if (setValue != null)
setValue(oldValue);
}
}
请注意,禁用转换器的逻辑需要是线程安全的,因为 Json.NET 将跨线程共享契约和转换器。
演示小提琴 #1here https://dotnetfiddle.net/jLThhS.
作为备选,您可以完全消除转换器并应用[JsonObject(IsReference = true)] https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonContainerAttribute_IsReference.htm直接到ModelBase
:
[JsonObject(IsReference = true)]
public abstract class ModelBase : IModelBase
{
public string ID { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime ModifiedAt { get; set; }
}
然后序列化和反序列化DefaultValueHandling.Ignore
and NullValueHandling.Ignore
在设置中指定,如下所示:
static object Deserialize(Stream streamFromWebAPICall, Type objectType)
{
using (var sr = new StreamReader(streamFromWebAPICall))
{
using (var jtr = new JsonTextReader(sr))
{
var settings = new JsonSerializerSettings
{
DefaultValueHandling = DefaultValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore,
};
var js = JsonSerializer.CreateDefault(settings);
return js.Deserialize(jtr, objectType);
}
}
}
演示小提琴#2here https://dotnetfiddle.net/C6Azs5.
注意你还可以设置[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)] https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonObjectAttribute_ItemNullValueHandling.htm as of Json.NET 11.0.1 https://github.com/JamesNK/Newtonsoft.Json/releases/tag/11.0.1,但似乎没有ItemDefaultValueHandling
设置为JsonObjectAttribute
,因此将其添加到序列化器设置中(或使用可空值作为可选值类型值,例如CreatedAt
) 是必须的。