skip to Main Content

When I debug the test below, the code hits the CanConvert method of the EmailadressenConverter class and that method returns true.

I was expecting the Read method to get hit next, but this never happens, resulting in an object that has null for property EmailZakelijk.

Why is the Read method not called?

I am using .NET 8, and this is my code:

public class EmailadressenConverter : JsonConverter<Emails>
{
    public override bool CanConvert(Type typeToConvert)
    {
        return base.CanConvert(typeToConvert);
    }

    public override Emails? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var ctorEmail = "";
        var optionalEmails = new List<string>();
        var currentPropertyName = "";

        while (reader.Read())
        {
            if (reader.TokenType == JsonTokenType.EndObject)
                break;

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                currentPropertyName = reader.GetString()!;
                continue;
            }

            if (string.Equals(currentPropertyName, nameof(Emailadressen.PrimairEmailAdres), StringComparison.CurrentCultureIgnoreCase))
                ctorEmail = reader.GetString()!;
        }

        if (string.IsNullOrEmpty(ctorEmail))
            return null;

        return new Emails(ctorEmail); 
    }

    public override void Write(Utf8JsonWriter writer, Emails value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        writer.WriteString(nameof(Emails.Email), value.Email.Value);
       
        writer.WriteEndObject();

        return;
    }
}

public class Emails
{
    public Emails(string primairEmailadres)
    {
        Email = new Emailadres(primairEmailadres);
    }

    public Emailadres Email { get; set; }
}

public class DummyMailClass
{
    public Emails? EmailZakelijk { get; set; }
}

public class EmailadressenJsonConverterTests
{
    [Fact]
    public void Deserialize_only_primair_emailadres()
    {
        var json = """
            {
                "emailZakelijk": {
                    "email": {
                        "value":"[email protected]"
                    }
                }
            }
            """;

        var options = new JsonSerializerOptions();
        //options.Converters.Clear();
        options.Converters.Add(new EmailadressenConverter());
        //options.Converters.Add(new EmailsConverterFactory());

        var dmc = JsonSerializer.Deserialize<DummyMailClass>(json, options);

        dmc.Should().NotBeNull();
        dmc!.EmailZakelijk.Should().NotBeNull();
        dmc.EmailZakelijk!.Email.Value.Should().Be("[email protected]");
    }
}

public partial record Emailadres
{
    public Emailadres(string value)
    {
        Value = value;
    }

    public string Value { get; private set; }
}

2

Answers


  1. Chosen as BEST ANSWER

    Turns out I hadn't set PropertyNameCaseInsensitive to true on JsonSerializerOptions. Very frustrating, I thought this was true by default.


  2. When you declare the JsonSerializerOptions instance, the default PropertyNamingPolicy is null. Thus, it is unable to convert for the emailZakelijk JSON object as it is in camel case.

    So either you need to provide PropertyNamingPolicy = JsonNamingPolicy.CamelCase

    var options = new JsonSerializerOptions()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    };
    

    Or specify PropertyNameCaseInsensitive = true in JsonSerializerOptions.

    var options = new JsonSerializerOptions()
    {
        PropertyNameCaseInsensitive = true
    };
    

    Note that I get the exception:

    JsonException: Read too much or not enough

    Thus, I revamp the Read logic as below:

    public override Emails? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        Console.WriteLine("Read");
        var ctorEmail = "";
        var optionalEmails = new List<string>();
        var currentPropertyName = "";
    
        while (reader.Read())
        {           
            if (reader.TokenType == JsonTokenType.StartObject)
            {
                continue;
            }
            else if (reader.TokenType == JsonTokenType.EndObject)
            {
                break;
            }
            else if (reader.TokenType == JsonTokenType.PropertyName)
            {
                currentPropertyName = reader.GetString()!;
    
                if (string.Equals(currentPropertyName, "email", StringComparison.CurrentCultureIgnoreCase))
                {
                    Emailadres emailadres = JsonSerializer.Deserialize<Emailadres>(ref reader, options);
                    ctorEmail = emailadres.Value;
                    reader.Skip();
                }
                continue;
            }
            else if (reader.TokenType == JsonTokenType.String)
            {
                ctorEmail = reader.GetString()!;
                break;
            }
        }
    
        if (string.IsNullOrEmpty(ctorEmail))
            return null;
    
        return new Emails(ctorEmail); 
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search