Runtime: JsonIgnore not respected if object is passed as interface

Created on 22 Aug 2020  路  2Comments  路  Source: dotnet/runtime

Description

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

public class Program
{
    public interface IB {
        public int C { get; }
        public int D { get; set; }
    }

    public class B : IB {
        [JsonIgnore]
        public int C => throw new Exception("i had JsonIgnore, but someone tried to serialize me :(");
        public int D { get; set; }
    }

    public class A {
        public IB B { get; set; }
    }

    public static void Main()
    {
        var a = new A();
        a.B = new B();
        a.B.D = 5;

        Console.WriteLine(JsonSerializer.Serialize(a));
    }
}

If object implementing an interface is passed into Serialize as interface, JsonIgnore is respected only on interface, not the class properties. In the code above, there is no way to work around it without modifying the classes themselves

Got:
Unhandled exception. System.Exception: i had JsonIgnore, but someone tried to serialize me :(
Expected:
{"B":{"D":5}}

Configuration

.NET Core 3.1, System.Text.Json 4.7.2

area-System.Text.Json

Most helpful comment

This behavior strikes me as correct. _System.Text.Json_ is using statically available metadata, which means that the metadata would be read from _IB_, not from _B_.

You should in theory see the same behavior if you had:

public class MyBaseClass
{
    public virtual int MyProperty { get; set; }
}

public class MyDerivedClass : MyBaseClass
{
    [JsonIgnore]
    public override int MyProperty { get; set; }
}

public void DoSerialization()
{
    MyDerivedClass obj = new MyDerivedClass { MyProperty = 42 };
    var serialized = JsonSerializer.Serialize<MyBaseClass>(obj);
    // 'serialized' is expected to contain { "MyProperty": 42 }
}

(I haven't tested this sample. But it's what I would expect to be output.)

All 2 comments

This behavior strikes me as correct. _System.Text.Json_ is using statically available metadata, which means that the metadata would be read from _IB_, not from _B_.

You should in theory see the same behavior if you had:

public class MyBaseClass
{
    public virtual int MyProperty { get; set; }
}

public class MyDerivedClass : MyBaseClass
{
    [JsonIgnore]
    public override int MyProperty { get; set; }
}

public void DoSerialization()
{
    MyDerivedClass obj = new MyDerivedClass { MyProperty = 42 };
    var serialized = JsonSerializer.Serialize<MyBaseClass>(obj);
    // 'serialized' is expected to contain { "MyProperty": 42 }
}

(I haven't tested this sample. But it's what I would expect to be output.)

@GrabYourPitchforks is correct.

(I haven't tested this sample. But it's what I would expect to be output.)

That is indeed the output - https://dotnetfiddle.net/mpqIt4.

When polymorphic support is extended, part of the design would be to honor metadata on the actual type a property is being (de)serialized as - https://github.com/dotnet/runtime/issues/30083, https://github.com/dotnet/runtime/issues/29937.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

v0l picture v0l  路  3Comments

yahorsi picture yahorsi  路  3Comments

GitAntoinee picture GitAntoinee  路  3Comments

Timovzl picture Timovzl  路  3Comments

EgorBo picture EgorBo  路  3Comments