C
C#13mo ago
Kiel

✅ JSON serializing Optional type throws an exception(?)

Newtonsoft.Json.JsonWriterException: Token PropertyName in state Property would result in an invalid JSON object. Path ''. Here's my JsonConverter:
public class OptionalJsonConverter : JsonConverter<IOptional>
{
public override void WriteJson(JsonWriter writer, IOptional? value, JsonSerializer serializer)
{
if (value is not { HasValue: true })
return;

var optionalValue = value.Value;
if (optionalValue is null)
{
writer.WriteNull();
}
else
{
serializer.Serialize(writer, optionalValue);
}
}

public override IOptional ReadJson(JsonReader reader, Type objectType, IOptional? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
// This calls a default constructor for an Optional<T> type.
return (IOptional) objectType.GetConstructors()[0].Invoke(new[] { serializer.Deserialize(reader, objectType.GenericTypeArguments[0]) });
}
}
public class OptionalJsonConverter : JsonConverter<IOptional>
{
public override void WriteJson(JsonWriter writer, IOptional? value, JsonSerializer serializer)
{
if (value is not { HasValue: true })
return;

var optionalValue = value.Value;
if (optionalValue is null)
{
writer.WriteNull();
}
else
{
serializer.Serialize(writer, optionalValue);
}
}

public override IOptional ReadJson(JsonReader reader, Type objectType, IOptional? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
// This calls a default constructor for an Optional<T> type.
return (IOptional) objectType.GetConstructors()[0].Invoke(new[] { serializer.Deserialize(reader, objectType.GenericTypeArguments[0]) });
}
}
I'm not quite sure what's going on here as it's difficult for me to debug what JSON is being serialized by the Serialize call or what Json.NET is trying to validate later on. Serializing to a StringBuilder instead of the writer yields a simple string property is being serialized, and yet this exception is being thrown. Google was very unhelpful as one of the only results for this exact error message was for something completely different, and the exception message doesn't really yield any clues. I found out about ITraceWriter, and here's what it was able to output:
2023-06-16T08:24:08.897 Info Started serializing Rivoltante.Rest.CreateMessageApiModel. Path ''.
2023-06-16T08:24:08.926 Info Started serializing Rivoltante.Core.Optional`1[System.String] with converter Rivoltante.Rest.OptionalJsonConverter. Path 'content'.
2023-06-16T08:24:08.931 Info Finished serializing Rivoltante.Core.Optional`1[System.String] with converter Rivoltante.Rest.OptionalJsonConverter. Path 'content'.
2023-06-16T08:24:08.932 Info Started serializing Rivoltante.Core.Optional`1[System.String[]] with converter Rivoltante.Rest.OptionalJsonConverter. Path 'attachments'.
2023-06-16T08:24:08.932 Info Finished serializing Rivoltante.Core.Optional`1[System.String[]] with converter Rivoltante.Rest.OptionalJsonConverter. Path 'attachments'.
2023-06-16T08:24:08.933 Error Error serializing Rivoltante.Rest.CreateMessageApiModel. Token PropertyName in state Property would result in an invalid JSON object. Path ''.
2023-06-16T08:24:08.897 Info Started serializing Rivoltante.Rest.CreateMessageApiModel. Path ''.
2023-06-16T08:24:08.926 Info Started serializing Rivoltante.Core.Optional`1[System.String] with converter Rivoltante.Rest.OptionalJsonConverter. Path 'content'.
2023-06-16T08:24:08.931 Info Finished serializing Rivoltante.Core.Optional`1[System.String] with converter Rivoltante.Rest.OptionalJsonConverter. Path 'content'.
2023-06-16T08:24:08.932 Info Started serializing Rivoltante.Core.Optional`1[System.String[]] with converter Rivoltante.Rest.OptionalJsonConverter. Path 'attachments'.
2023-06-16T08:24:08.932 Info Finished serializing Rivoltante.Core.Optional`1[System.String[]] with converter Rivoltante.Rest.OptionalJsonConverter. Path 'attachments'.
2023-06-16T08:24:08.933 Error Error serializing Rivoltante.Rest.CreateMessageApiModel. Token PropertyName in state Property would result in an invalid JSON object. Path ''.
1 Reply
Kiel
Kiel13mo ago
I figured out the issue, I'm not serializing the property value, but the property name is still getting serialized. I haven't solved that problem, but at least I know the cause now