Skip to content

JSON Serialize as object doesn't work with source generation by default #84704

@eerhardt

Description

@eerhardt

Description

In order to solve polymorphic JSON serialization scenarios in ASP.NET, specifically in ASP.NET's EndpointFilterDelegate which uses object as the "declared type", we need to serialize the value "as object". However, this doesn't work with source generation by default unless the user explicitly adds typeof(object) to the source generated context.

Reproduction Steps

Run:

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

var value = new Derived() { BaseString = "Base", DerivedString = "Derived" };

var options = new JsonSerializerOptions();
options.TypeInfoResolver = new TestJsonContext();

Console.WriteLine(JsonSerializer.Serialize<object>(value, options));

internal class Base
{
    public string? BaseString { get; set; }
}

internal class Derived : Base
{
    public string? DerivedString { get; set; }
}

[JsonSerializable(typeof(Base))]
[JsonSerializable(typeof(Derived))]
internal partial class TestJsonContext : JsonSerializerContext { }

Expected behavior

Should output

{"DerivedString":"Derived","BaseString":"Base"}

Actual behavior

System.NotSupportedException
  Message=JsonTypeInfo metadata for type 'System.Object' was not provided by TypeInfoResolver of type 'TestJsonContext'. If using source generation, ensure that all root types passed to the serializer have been annotated with 'JsonSerializableAttribute', along with any types that might be serialized polymorphically.
  StackTrace:
   at System.Text.Json.ThrowHelper.ThrowNotSupportedException_NoMetadataForType(Type type, IJsonTypeInfoResolver resolver) in /_/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs:line 726
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable, Boolean fallBackToNearestAncestorType) in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs:line 90
   at System.Text.Json.JsonSerializerOptions.get_ObjectTypeInfo() in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs:line 144
   at System.Text.Json.JsonSerializer.GetTypeInfo[T](JsonSerializerOptions options) in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs:line 54
   at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options) in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs:line 32
   at Program.<Main>$(String[] args) in C:\DotNetTest\Net8Console\Program.cs:line 9

Regression?

No response

Known Workarounds

A workaround is to add

[JsonSerializable(typeof(object))]

To the TestJsonContext.

Configuration

No response

Other information

One concern is that we shouldn't regress the Native AOT size by too much by fixing this problem. Our current goal is to have a ~10 MB native executable for the dotnet new api -aot template. Fixing this issue can't take up too much of that 10 MB goal. We should measure and ensure we aren't adding too much size to fix this (for example by rooting a bunch of converters that are not necessary).

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-System.Text.Jsonpartner-impactThis issue impacts a partner who needs to be kept updatedsource-generatorIndicates an issue with a source generator feature

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions