andrewlock / StronglyTypedId

A Rosyln-powered generator for strongly-typed IDs
MIT License
1.5k stars 78 forks source link

Specify converter for JsonSerializerContext #141

Open fleed opened 2 weeks ago

fleed commented 2 weeks ago

When using version 1.0.0-beta08 of the library in a .net 8 app, if you specify a System.Text.Json.Serialization.JsonSerializerContext, the StronglyTypedId will be serialized as an empty object.

Definition:

[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, Converters = [typeof(ProjectId.ProjectIdSystemTextJsonConverter)])]
[JsonSerializable(typeof(Project))]
internal partial class ProjectSourceContext : JsonSerializerContext
{
}

Ideal usage:

[Fact]
    public async Task TestProjectSerializationDefaultAsync()
    {
        var project = new Project
        {
            Id = new ProjectId(new Guid("00000000-0000-0000-0000-000000000001")),
            Name = "Project 1"
        };
        var serialized = JsonSerializer.Serialize(project, ProjectSourceContext.Default.Project);
        await Verify(serialized);
    }

Value of serialized string:

{"id":{},"name":"Project 1"}

I am currently using the following solution:

[Fact]
    public async Task TestProjectSerializationAsync()
    {
        var project = new Project
        {
            Id = new ProjectId(new Guid("00000000-0000-0000-0000-000000000001")),
            Name = "Project 1"
        };
        var options = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };
        options.Converters.Add(new ProjectId.ProjectIdSystemTextJsonConverter());
        var context = new ProjectSourceContext(options);
        var serialized = JsonSerializer.Serialize(project, context.Project);
        await Verify(serialized);
    }

In this case, you will get the expected JSON: {"id":"00000000-0000-0000-0000-000000000001","name":"Project 1"}. If you comment out the line options.Converters.Add(), you will still receive the incorrect serialized string with an empty object as the id.

This is the ideal solution I'm looking for:

[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, Converters = [typeof(ProjectId.ProjectIdSystemTextJsonConverter)])]
[JsonSerializable(typeof(Project))]
internal partial class ProjectSourceContext : JsonSerializerContext
{
}

but I'm receiving the following compilation error:

Error SYSLIB1220 : The 'JsonConverterAttribute' type 'TestApp.Model.ProjectId.ProjectIdSystemTextJsonConverter' specified on member 'TestApp.Model.ProjectSourceContext' is not a converter type or does not contain an accessible parameterless constructor.

Is there another way to specify the converter for the Default serializer context object, to avoid specifying the options everywhere?