Skip to content

The JsonIgnore is being ignored causing property collisions with PropertyNameCaseInsensitive set to true #93903

@normj

Description

@normj

Description

I'm updating our JSON serialization code for AWS Lambda to support .NET 8 and ran into a serialization bug that was worked correctly in previous versions. When doing JSON serialization with System.Text.Json and PropertyNameCaseInsensitive set to true properties with JsonIgnore are being included when detecting attribute collisions. For example looking at following type

public class MyPoco
{
    [JsonPropertyName("approximateArrivalTimestamp")]
    public long ApproximateArrivalEpoch { get; set; }

    [JsonIgnore]
    public DateTime ApproximateArrivalTimestamp
    {
        get
        {
            var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            return epoch.AddMilliseconds(ApproximateArrivalEpoch);
        }
    }
}

There are technically 2 properties with the name approximateArrivalTimestamp but since the one that returns DateTime has the JsonIgnore attribute it should be ignored during serialization but instead I get an exception about a conflict between the 2. This example uses attributes to demonstrate because this is what I'm using in my code but I can reproduce this issue without attributes and just using different casing for the property names.

public class MyPoco
{
    public long approximateArrivalTimestamp { get; set; }

    [JsonIgnore]
    public DateTime ApproximateArrivalTimestamp
    {
        get
        {
            var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            return epoch.AddMilliseconds(approximateArrivalTimestamp);
        }
    }
}

Reproduction Steps

Run the following code and you will get a naming collision for approximateArrivalTimestamp. There shouldn't be a collision because the ApproximateArrivalTimestamp property has the JsonIgnore attribute which should exclude it from collisions.

using System.Text.Json;
using System.Text.Json.Serialization;

namespace JsonAttributeTest;

internal class Program
{
    static void Main(string[] args)
    {
        var options = new JsonSerializerOptions
        {
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
            PropertyNameCaseInsensitive = true,
        };

        var poco = new MyPoco { ApproximateArrivalEpoch = 1698106445L };
        
        var json = JsonSerializer.Serialize(poco, options);

        var serializedPoco = JsonSerializer.Deserialize<MyPoco>(json, options);
        Console.WriteLine(serializedPoco.ApproximateArrivalTimestamp);
    }
}

public class MyPoco
{
    [JsonPropertyName("approximateArrivalTimestamp")]
    public long ApproximateArrivalEpoch { get; set; }

    [JsonIgnore]
    public DateTime ApproximateArrivalTimestamp
    {
        get
        {
            var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            return epoch.AddMilliseconds(ApproximateArrivalEpoch);
        }
    }
}

Expected behavior

The MyPoco is successfully serialized to

{
  "approximateArrivalTimestamp": 1698106445
}

and then deserialized back into a new POCO.

Actual behavior

Get a System.InvalidOperationException with the following error message:

The JSON property name for 'JsonAttributeTest.MyPoco.ApproximateArrivalTimestamp' collides with another property.

Regression?

Yes. Same code works .NET 6 and earlier.

Known Workarounds

These are .NET types used to represent AWS Lambda event and our part of our public contract. I can't change the .NET property names to work around the issue because that would be a breaking change. If these were new types then I could change the .NET names to be unique and not rely on the Json attribute.

Configuration

Fails on .NET 8 RC2 but works in earlier versions.

Other information

No response

Metadata

Metadata

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions