Can I make Json.net deserialize a C# 9 record type with the “primary” constructor, as if it had [JsonConstructor]?

Firstly, you only have to do this when you create your own constructors. This is due to the fact that on instantiation it won’t know which one to use.

Secondly, note that (by default) the deserializer will use the property and constructor names and overwrite the ones you omit in the actual constructor type. Furthermore, each parameter in the constructor must bind to an object property or field on deserialization. The formers can lead to subtle errors if you are not aware of them, however this is not limited solely to records.

All that aside, you had the attribute in the wrong place. In short, the attribute needs to be on the constructor.

Wildly contrived nonsensical example:

Given

public record TestRecord(Guid Id)
{
   [JsonConstructor]
   public TestRecord(object theThing, string whatHappened) : this(Guid.NewGuid())
   {
   }
}

Test

var record = new TestRecord(Guid.NewGuid());
var json = JsonConvert.SerializeObject(record,Formatting.Indented);
Console.WriteLine(json);
var otherSideRecord = JsonConvert.DeserializeObject<TestRecord>(json);

// note this paradoxically still works, because it has overwritten the ID
Console.WriteLine(record == otherSideRecord);

Ouput

{
  "Id": "2905cfaf-d13d-4df1-af83-e4dcde20d44f"
}
True

Note that the attribute also works with Text.Json

var json = JsonSerializer.Serialize(record);
var otherSideRecord = JsonSerializer.Deserialize<TestRecord>(json);

Leave a Comment