Skip to content

Using JSON Source Gen with an Object property roots all JsonConverters #52943

Description

@eerhardt

Using System.Text.Json source generation in my application isn't providing for size reductions in the app because all the JsonConverters are still being rooted in the app.

Similar to #52662, but now because I have the object Value property in my WeatherForecast class.

Repro

using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using ConsoleApp13;
using ConsoleApp13.JsonSourceGeneration;

[assembly: JsonSerializable(typeof(WeatherForecast))]

namespace ConsoleApp13
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string f = @"{""TemperatureC"":0,""Summary"":""hi""}";

            var forecast = JsonSerializer.Deserialize(f, new JsonContext().WeatherForecast);
            Console.WriteLine(forecast);
        }
    }

    public record WeatherForecast
    {
        public DateTime Date { get; set; }

        public int TemperatureC { get; set; }

        public string Summary { get; set; }

        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

        public object Value { get; set; }
    }
}

dotnet publish -r win-x64 -c Release -p:PublishTrimmed=true -p:DebuggerSupport=false -p:TrimmerSingleWarn=false

View the outputted assemblies, and notice that System.Text.Json.dll is ~275KB and still has all its JsonConverters in it.

Analysis

From looking at the results, the reason everything is still rooted is because of the following call graph:

  • The source gen'd JsonContext class for WeatherForecast has a public JsonTypeInfo<object> Object property that references JsonMetadataServices.ObjectConverter.
  • JsonMetadataServices.ObjectConverter is a System.Text.Json.Serialization.Converters.ObjectConverter instance.
  • ObjectConverter takes a direct dependency on JsonNodeConverter.Instance
  • JsonNodeConverter creates new JsonValue<T>
  • JsonValue<T>.ToString calls JsonSerializer.Serialize without source gen information

That this point, since JsonSerializer.Serialize is called without source gen information, it now roots all JsonConverters, and the size of the app grows by a lot.

(Note that this pattern exists in ASP.NET Blazor WASM)

cc @layomia @steveharter @marek-safar @vitek-karas @CoffeeFlux

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions