Specify converter for JsonSerializerContext
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?
Hey, sorry for the delay, I managed to miss this... did you ever get to the bottom of the issue? I've just given it a try and I can see that it has the behaviour you describe, but I'm not sure why 🤔 It's as though the source generator just isn't paying any attention to the Converters attribute for some reason (annoyingly the docs on it are very light too).
EDIT: ~I can't reproduce the compiler error you're seeing at all though 🤔 Which .NET version are you using? Neither .NET 8 or .NET 9 give the compilation error for me.~
I stand corrected, I can reproduce the error, and that's likely the source of the issue. I haven't figured out why yet though...
Ok, I've just figured it out.
Source generators can't see the output of other source generators. So the Json Source Generator can't see the the converter generated by StronglyTypedId, hence the slightly strange compilation error.
Unfortunately, currently, there's no workaround for this, other than having the IDs defined in a different project to the project in which you're creating your JsonSerializerContext I think 🙁 Yes, that kinda sucks, but it's a limitation in the compiler currently.
One possible workaround is the approach I use in the tests:
https://github.com/andrewlock/StronglyTypedId/blob/2313453da5db3dced61bcb99b82e9443f7f22367/test/StronglyTypedIds.IntegrationTests/SystemTextJsonSerializerContext.cs#L18-L30
This doesn't help with the Default case, but it does mean you can do something like this:
[JsonSerializable(typeof(Project))]
internal partial class ProjectSourceContext : JsonSerializerContext
{
internal static SystemTextJsonSerializerContext Custom
=> new(new JsonSerializerOptions
{
Converters =
{
new ProjectId.ProjectIdSystemTextJsonConverter(),
}
});
}
And then you can use it like this:
var serialized = JsonSerializer.Serialize(project, ProjectSourceContext.Custom.Project);