1

I recently spent a lot of time upgrading my old asp.net 4.6 project to .Net 6.

I have almost everything working, but I am having trouble using System.Text.Json in place of Newtonsoft.

In my Startup.cs I ham trying to use a Custom Converter like this:

services.AddMvc()
    .AddJsonOptions(opts => {
        //custom converter for PlayerItemDto
        opts.JsonSerializerOptions.Converters.Add(new PlayerItemConverter());
    });
    
    

Here is where I am trying to do the conversion. This is all Newtonsoft now, and I am not sure if this will work in System.Text.Json.

Specifically, I can't find anything in System.Text.Json that replaces var obj = JObject.Load(reader); and options.Populate(obj.CreateReader(), retval)

Does anyone know if it's possible?

Here is my converter class:

public class PlayerItemConverter : CustomCreationConverter<PlayerItemDto>
{
    public PlayerItemDto Create(String morality)
    {
        switch (morality) {
            case "bad":
                return new MonsterTypeDto();
            case "good":
                return new LeaderTypeDto();
        }
    }

    public override Object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var obj = JObject.Load(reader);
        var morality = (String) obj.Property("morality");
        var retval = Create(morality);
        serializer.Populate(obj.CreateReader(), retval);
        return retval;
    }
}
SkyeBoniwell
  • 6,345
  • 12
  • 81
  • 185
  • 1
    Is `PlayerItemDto` an abstract base type for `MonsterTypeDto` and `LeaderTypeDto`? If so, then see [Is polymorphic deserialization possible in System.Text.Json?](https://stackoverflow.com/q/58074304/3744182). I specifically like [this answer](https://stackoverflow.com/a/66352365/3744182) by [Somaar](https://stackoverflow.com/users/2342856/somaar) as being the closest to Json.NET's `CustomCreationConverter`. – dbc May 26 '22 at 19:37

1 Answers1

4

Your converter needs to derive from JsonConverter, and the implement CanConvert, Read and Write e.g.:

public class PlayerItemConverter : JsonConverter<PlayerItemDto>
{
    public override bool CanConvert(Type typeToConvert)
    {
        return typeof(PlayerItemDto).IsAssignableFrom(typeToConvert);
    }   

    public override PlayerItemDto Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using (JsonDocument jsonDoc = JsonDocument.ParseValue(ref reader))
        {
            // Convert your jsonDoc into a PlayerItemDto and return it
        }
    }

    public override void Write(Utf8JsonWriter writer, PlayerItemDto value, JsonSerializerOptions options)
    {
        JsonSerializer.Serialize(writer, value, options);
    }
    
}

You can then either register your converter, or declare it using an attribute on the class, e.g.:

[JsonConverter(typeof(PlayerItemConverter))]
public class PlayerItemDto
{
}

UPDATE

Considering classes:

public class PlayerItemDto
{
    public string Name { get; set; }
    public int Age { get; set; }
    public AddressDto Address { get; set; }
}

public class AddressDto
{
    public int HouseNumber { get; set; }
    public string Street { get; set; }
}

You can access properties using:

using (JsonDocument jsonDoc = JsonDocument.ParseValue(ref reader))
{
    string name = jsonDoc.RootElement.GetProperty("Name").GetString();
    int age = jsonDoc.RootElement.GetProperty("Age").GetInt32();
    int houseNumber = jsonDoc.RootElement.GetProperty("Address").GetProperty("HouseNumber").GetInt32();
    string street = jsonDoc.RootElement.GetProperty("Address").GetProperty("Street").GetString();

    // Build your PlayerItemDto from the properties
}
Neil W
  • 7,670
  • 3
  • 28
  • 41