Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsonSerializer.Serialize overloads accepting JsonSerializerContext don't support unspeakable types. #84260

Closed
Tracked by #79122
DamianEdwards opened this issue Apr 3, 2023 · 4 comments
Assignees
Labels
area-System.Text.Json bug source-generator Indicates an issue with a source generator feature
Milestone

Comments

@DamianEdwards
Copy link
Member

DamianEdwards commented Apr 3, 2023

Description

When using the System.Text.Json source generator, attempting to serialize a compiler-generated instance of IAsyncEnumerable<T> throws an exception saying a TypeInfo could not be found.

Reproduction Steps

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

var stream = new MemoryStream();
var todos = GetTodosAsync(10);
await JsonSerializer.SerializeAsync(stream, todos, todos.GetType(), AppJsonSerializerContext.Default);

async IAsyncEnumerable<Todo> GetTodosAsync(int count)
{
    for (int i = 0; i < count; i++)
    {
        await Task.Delay(10);
        yield return new Todo { Id = i, Name = $"Todo {i}" };
    }
}

class Todo
{
    public int Id { get; set; }
    public string? Name { get; set; }
}

[JsonSerializable(typeof(IAsyncEnumerable<Todo>))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{

}

Expected behavior

The result gets serialized.

Actual behavior

An exception is thrown:

System.InvalidOperationException
  HResult=0x80131509
  Message=JsonTypeInfo metadata for type 'Program+<<<Main>$>g__GetTodosAsync|0_0>d' was not provided by TypeInfoResolver of type 'AppJsonSerializerContext'. 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.
  Source=System.Text.Json
  StackTrace:
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_NoMetadataForType(Type type, IJsonTypeInfoResolver resolver) in /_/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs:line 743
   at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerContext context, Type inputType) in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs:line 50
   at System.Text.Json.JsonSerializer.Serialize(Object value, Type inputType, JsonSerializerContext context) in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs:line 152
   at Program.<Main>$(String[] args) in C:\Users\damia\source\repos\JsonAsyncEnumerable\JsonAsyncEnumerable\Program.cs:line 5

Regression?

No, but this was expected to work after the recent changes to support unspeakable types in the JSON source generator.

Known Workarounds

None.

Configuration

SDK version: 8.0.100-preview.3.23178.7
Runtime version: 8.0.0-preview.3.23174.8
OS: Windows 11 x64 22H2

Other information

No response

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Apr 3, 2023
@ghost
Copy link

ghost commented Apr 3, 2023

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

When using the System.Text.Json source generator, attempting to serialize a compiler-generated instance of IAsyncEnumerable<T> throws an exception saying a TypeInfo could not be found.

Reproduction Steps

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

var todos = GetTodosAsync(10);
var json = JsonSerializer.Serialize(GetTodosAsync(10), todos.GetType(), AppJsonSerializerContext.Default);

async IAsyncEnumerable<Todo> GetTodosAsync(int count)
{
    for (int i = 0; i < count; i++)
    {
        await Task.Delay(10);
        yield return new Todo { Id = i, Name = $"Todo {i}" };
    }
}

class Todo
{
    public int Id { get; set; }
    public string? Name { get; set; }
}

[JsonSerializable(typeof(IAsyncEnumerable<Todo>))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{

}

Expected behavior

The result gets serialized.

Actual behavior

An exception is thrown:

System.InvalidOperationException
  HResult=0x80131509
  Message=JsonTypeInfo metadata for type 'Program+<<<Main>$>g__GetTodosAsync|0_0>d' was not provided by TypeInfoResolver of type 'AppJsonSerializerContext'. 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.
  Source=System.Text.Json
  StackTrace:
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_NoMetadataForType(Type type, IJsonTypeInfoResolver resolver) in /_/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs:line 743
   at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerContext context, Type inputType) in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Helpers.cs:line 50
   at System.Text.Json.JsonSerializer.Serialize(Object value, Type inputType, JsonSerializerContext context) in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.String.cs:line 152
   at Program.<Main>$(String[] args) in C:\Users\damia\source\repos\JsonAsyncEnumerable\JsonAsyncEnumerable\Program.cs:line 5

Regression?

No, but this was expected to work after the recent changes to support unspeakable types in the JSON source generator.

Known Workarounds

None.

Configuration

SDK version: 8.0.100-preview.3.23178.7
Runtime version: 8.0.0-preview.3.23174.8
OS: Windows 11 x64 22H2

Other information

No response

Author: DamianEdwards
Assignees: -
Labels:

area-System.Text.Json, untriaged

Milestone: -

@eerhardt
Copy link
Member

eerhardt commented Apr 3, 2023

We think this should be fixed by dotnet/aspnetcore#47548. Is that right @eiriktsarpalis?

@eiriktsarpalis
Copy link
Member

eiriktsarpalis commented Apr 4, 2023

@eerhardt That's correct when it comes to using GetTypeInfo, since it cannot be made to work with unspeakable types.

When it comes to the particular repro, the reason why JsonSerializerContext fails to work with unspeakable types is because it uses its own metadata resolution logic:

private static JsonTypeInfo GetTypeInfo(JsonSerializerContext context, Type inputType)
{
Debug.Assert(context != null);
Debug.Assert(inputType != null);
JsonTypeInfo? info = context.GetTypeInfo(inputType);
if (info is null)
{
ThrowHelper.ThrowInvalidOperationException_NoMetadataForType(inputType, context);
}
info.EnsureConfigured();
return info;
}

I had wanted to shim these methods over their JsonSerializerOptions counterparts, but annoyingly they throw InvalidOperationException instead of NotSupportedException -- so it would force a breaking change. This should be fixed in conjunction with #81269 and we might want to consider taking that breaking change.

cc @krwq @layomia

@eiriktsarpalis eiriktsarpalis removed the untriaged New issue has not been triaged by the area owner label Apr 4, 2023
@eiriktsarpalis eiriktsarpalis added this to the 8.0.0 milestone Apr 4, 2023
@eiriktsarpalis eiriktsarpalis added the source-generator Indicates an issue with a source generator feature label Apr 4, 2023
@eiriktsarpalis eiriktsarpalis self-assigned this Apr 4, 2023
@eiriktsarpalis eiriktsarpalis changed the title JSON source generator can't serialize IAsyncEnumerable JsonSerializer.Serialize overloads accepting JsonSerializerContext don't support unspeakable types. Apr 4, 2023
@eiriktsarpalis
Copy link
Member

The changes in #84768 reverted support for unspeakable types in overloads that accept explicit Type parameters, it now only kicks in when serializing values of declared type object. Given @eerhardt's plan in dotnet/aspnetcore#47548 (comment) I'm going to close this as out of scope for Goldilocks.

@eiriktsarpalis eiriktsarpalis closed this as not planned Won't fix, can't repro, duplicate, stale Apr 19, 2023
@ghost ghost locked as resolved and limited conversation to collaborators May 19, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Text.Json bug source-generator Indicates an issue with a source generator feature
Projects
None yet
Development

No branches or pull requests

3 participants