aspnet / AspNetWebStack

ASP.NET MVC 5.x, Web API 2.x, and Web Pages 3.x (not ASP.NET Core)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ObjectContent does not serialize root type with Auto TypeNameHandling

skatanski opened this issue · comments

Title

ObjectContent with JsonMediaTypeFormatter does not serialize root type with TypeNameHandling set to Auto

Functional impact

With TypeNameHandling set to Auto, the root type has to be passed into the SerializeObject or Serialize method (https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_TypeNameHandling.htm). This issue causes root type information of the object not be passed along and serialized to Json and forces user to use either TypeNameHandling.All or some other mechanism to correctly serialize the root type. For instance using JsonConvert.SerializeObject or a JsonSerializer directly works just fine.

Reproduction steps:

Here's the minimum code snippet to reproduce:

    class Program
    {
        class Animal
        {
            public string Name { get; init; }
        }

        class Bird : Animal
        {
            public Wing[] Leg { get; init; }
        }

        class Wing
        {
            public int Length { get; init; }
        }

        class FunnyWing : Wing
        {
        }

        static async Task Main()
        {
            var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
            var formatter = new JsonMediaTypeFormatter { SerializerSettings = settings };

            var duck = new Bird { Leg = new[] { new FunnyWing { Length = 5 } }, Name = "Duck" };

            var correctSerialization = JsonConvert.SerializeObject(duck, typeof(Animal), formatter.SerializerSettings);
            Console.WriteLine(correctSerialization);

            var content = new ObjectContent(typeof(Animal), duck, formatter, new MediaTypeHeaderValue("application/json"));
            var faultySerialization = await content.ReadAsStringAsync();
            Console.WriteLine(faultySerialization);
        }
    }

Expected result:

{"$type":"SerializationTest.Program+Bird, SerializationTest","Leg":[{"$type":"SerializationTest.Program+FunnyWing, SerializationTest","Length":5}],"Name":"Duck"}
{"$type":"SerializationTest.Program+Bird, SerializationTest","Leg":[{"$type":"SerializationTest.Program+FunnyWing, SerializationTest","Length":5}],"Name":"Duck"}

Actual result:

{"$type":"SerializationTest.Program+Bird, SerializationTest","Leg":[{"$type":"SerializationTest.Program+FunnyWing, SerializationTest","Length":5}],"Name":"Duck"}
{"Leg":[{"$type":"SerializationTest.Program+FunnyWing, SerializationTest","Length":5}],"Name":"Duck"}

Further technical details:

I've found the cause for this inside BaseJsonMediaTypeFormatter. There's an internal JsonSerializer, which doesn't receive Type parameter of the encompassing method.
This type parameter:
https://github.com/aspnet/AspNetWebStack/blob/main/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs#L411
Is not passed in here:
https://github.com/aspnet/AspNetWebStack/blob/main/src/System.Net.Http.Formatting/Formatting/BaseJsonMediaTypeFormatter.cs#L433

I've added type parameter, which fixed the issue:
skatanski@03124a6

I'd be happy to add some tests and create a pull request, however it seems this code base doesn't currently take in any PRs.

commented

Thanks for contacting us. This is a good catch, but we won't be able to take this change, as this changes existing behavior which many customers depend on.