1

I want to use polymorphic JSON for the RichText type in .NET 10 because I plan migrating from one richtext format to another and I am stuck with a problem: when the object is automatically serialized when being sent to a client, everything is fine, the type discriminator is present and everything works.

But when serizlizing it to store in the database, it does include the type discriminator in the resulting JSON, but at the end, not in the beginning. As you know, it is an issue when deserializing back because .NET requires the discriminator to be the first field in the JSON.

Here is the interface type:

[JsonPolymorphic(TypeDiscriminatorPropertyName = "$type")]
[JsonDerivedType(
    derivedType: typeof(DeltaRichText),
    typeDiscriminator: DeltaRichText.TypeDiscriminator
)]
public interface IRichTextType;

And here one of the implementations (currently I only have one):

public class DeltaRichText : IRichTextType
{
    public const string TypeDiscriminator = "delta";

    [Required]
    [MinLength(1)]
    [JsonPropertyName("ops")]
    public List<DeltaOp> Ops { get; set; } = [];

    /// <summary>
    /// Default constructor for DeltaRichText.
    /// Initializes the Ops property with an empty DeltaOp.
    /// </summary>
    public DeltaRichText()
    {
        Ops = [DeltaOp.Empty()];
    }

    public override string? ToString()
    {
        return JsonSerializer.Serialize<IRichTextType>(this);
    }

    // some other code...
}

Then, I added a converter in the DbContext:

new ValueConverter<IRichTextType?, string?>(
                v => v == null ? null : v.ToString(),
                v => v == null ? null : JsonSerializer.Deserialize<IRichTextType>(v, JsonSerializerOptions.Web)
            );

Things I tried that do not work:

  • add polymorphic attributes to the derived types (in this case the DeltaRichText) too
  • adding manually the Type property to every derived type with [JsonPropertyName('$type')] and [JsonPropertyOrder(-1)]

It seems it can be solved by creating a custom converter or by creating a Dictionary<string, object?> with the correct order manually and then serializing it. But it seems too much for such an issue and it does not solve it, but creates some huge workaround.

There is no problem when sending to the client, not to the database. I do not serizlize it myself but return it from the controller. In the Program.cs, I do not add some extra json properties or customization. In the DBContext, I use JsonSerializerOptions.Web, but it does not work with any of the options available.

5
  • The only simple options that works now is adding AllowOutOfOrderMetadataProperties = true in the JsonSerializerOptions. But this is not ideal since some parsers and apps rely on the metadata properties to be first Commented Nov 13 at 14:33
  • 3
    Can you please share a full minimal reproducible example somewhere like github for a lazy person like me? Commented Nov 13 at 17:51
  • I can't reproduce this in a .NET 10 console app. If I create a ValueConverter<IRichTextType?, string?> and call ConvertToProvider on an IRichTextType iRichText = new DeltaRichText(); instance, the "$type" parameter is emitted first. See dotnetfiddle.net/rxQsd0. Is there any chance that your database might be shredding and re-ordering the properties? Or that, when you fetch the JSON value from the database, you are selecting them in such a way that they are reordered? Commented Nov 13 at 18:29
  • Also, what column type are you using for your JSON? nvarchar? JSON data type? Somethine else? Alternatively, can you modify my fiddle to demonstrate your problem in a standalone console app? Commented Nov 13 at 18:34
  • @dbc indeed, it works in your fiddle... I use mysql 8.4, json column type. In the mysql docs I found that it does reorder the props and the order can't be relied on. Thanks! Commented Nov 14 at 11:10

1 Answer 1

3

Thanks to @dbc. The problem was not in the .NET itself, but with a database (in my case MySQL 8.4), which did reorder the JSON props. MySQL can and do normalize/reorder the JSON object so the order cannot be relied on, so the only option in this case is adding AllowOutOfOrderMetadataProperties = true in the JsonSerializerOptions.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.