Skip to content

C sharp and JSON

  • At least as of mid 2024, the built-in System.Text.Json stuff seems pretty powerful.
  • The official Microsoft documentation is good (although sometimes long).
  • Note to self: I worked somewhat extensively with JSON stuff for Skeleseller, so if I’m ever looking for code in the future, check there. To anyone else reading this, the source is closed at the time of writing. 😢

A custom converter is serializing incorrectly

Section titled A custom converter is serializing incorrectly
{
"$type": "HeldItemComponent",
"Item":
"id": 1 // ← ❌ This isn't valid JSON
}

This is the fault of the custom converter I wrote:

public class ItemConverter : JsonConverter<Item>
{
public override Item Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return Item.Create((ItemId)reader.GetInt32());
}
public override void Write(Utf8JsonWriter writer, Item value, JsonSerializerOptions options)
{
writer.WriteNumber(System.Text.Encoding.UTF8.GetBytes("id"), (int)value.Id);
}
}

Depending on what you want, there are two different fixes:

  • If the JSON you want is "Item": { "id": 1 }, then surround the call to writer.WriteNumber with writer.WriteStartObject(); and writer.WriteEndObject();
    • This also requires a change to the reader (see below); you generally need to loop on reader.Read() and check for when reader.TokenType is JsonTokenType.StartObject, JsonTokenType.EndObject, or JsonTokenType.PropertyName.
  • If the JSON you want is "Item": 1, then replace writer.WriteNumber with writer.WriteNumberValue.

Similarly, if you wanted to write arrays, you need to explicitly call WriteStartArray and WriteEndArray.

This is kind of ridiculous, but here’s how you would read the { "id": 1 } object. I didn’t need a loop since I only write one value:

public override Item Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
reader.Read();
// Get the key
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
// Ensure its value is correct
string? propertyName = reader.GetString();
if (propertyName != "id")
{
throw new JsonException();
}
reader.Read();
// Get the value
ItemId itemId = (ItemId)reader.GetInt32();
// Ensure we found the end of the object
reader.Read();
if (reader.TokenType == JsonTokenType.EndObject)
{
return Item.Create(itemId);
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, Item value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteNumber(System.Text.Encoding.UTF8.GetBytes("id"), (int)value.Id);
writer.WriteEndObject();
}