My Api returns a property which is effectively internal, and I do not expect such a property to be returned.
The situation
I have a simple public class Bar
with a public property, and an internal class FooBar
which inherits from Bar
and adss a public property. However, because the class is internal, that property is effectively also internal, not public.
public class Bar
{
public string PublicPropertyInPublicBaseClass { get; set; }
}
internal class FooBar : Bar
{
public string PublicPropertyInInternalClass { get; set; }
}
My controller action specifies it returns a Bar
, but the actual instance it returns is of type FooBar
.
[HttpGet]
public Bar Get()
{
return new FooBar();
}
The controller action returns:
{"publicPropertyInInternalClass":null,"publicPropertyInPublicBaseClass":null}
I would expect the Json serializer to only expose the properties of specified type (Bar
), so I would not expect publicPropertyInInternalClass
. And even if it is expected to expose the properties of the actual type, I would expect it to never expose a property of an internal type.
What I've tried
If I understand correctly, .NET Core 3.1 and higher uses System.Text.Json in stead of the older NewtonSoft.Json. I wrote a simple test to see what System.Text.Json would do and what NewtonSoft.Json does.
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestNetCoreSerializer()
{
Bar sut = CreateBar();
var serialized = System.Text.Json.JsonSerializer.Serialize(sut);
Debug.WriteLine(serialized);
// {"PublicPropertyInPublicBaseClass":null}
}
[TestMethod]
public void TestNewtonSoftSerializer()
{
Bar sut = CreateBar();
var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(sut);
Debug.WriteLine(serialized);
// {"PublicPropertyInInternalClass":null,"PublicPropertyInPublicBaseClass":null}
}
private static Bar CreateBar()
{
// We actually return a FooBar, which inherits from Bar
return new FooBar();
}
}
So now I am confused. The System.Text.Json serializer only exposes the property that is realy public, and I'd expect the controller to use that serializer. But what the controller returns seems to be the NewtonSoft.Json behavior.
What is going on here? Is the behavior I'm seeing expected? Why? Why would a serializer serialize the actual type? And why is this different between NewtonSoft.Json and System.Text.Json?
And maybe the most important question: am I doing something wrong by having an internal class inherit from a public class while that public class is part of the output model of my API? Or by having a public
property in an internal
class?
I've tried this also with both .NET Core 3.1 and .NET 5.0.