dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.23k stars 9.95k forks source link

Api return IAsyncEnumerable<> get errors when AddJsonOptions with custom json converter extend from JsonConverter<object> #54374

Open duc01226 opened 6 months ago

duc01226 commented 6 months ago

Is there an existing issue for this?

Describe the bug

Below is my custom JsonConverter:

public class PlatformObjectJsonConverter : JsonConverter<object>
{
    public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // My Custom Read code logic here

        return base.Read(ref reader, typeToConvert, options);
    }

    public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
    {
        // Let the default.NET behavior handle write object
        JsonSerializer.Serialize(writer, value, value.GetType(), removedItSelfOptions);
    }
}

Below is my test IAsyncEnumerable api:

    [HttpGet]
    [Route("TestIAsyncEnumerable")]
    public IAsyncEnumerable<string> TestIAsyncEnumerable()
    {
        return GetAsyncContent();
    }

    private async IAsyncEnumerable<string> GetAsyncContent()
    {
        for (var i = 0; i < int.MaxValue; i++)
            yield return await Task.Run(() => Guid.NewGuid().ToString());
    }

I added it into the mvc JSON options. When I declare API return IAsyncEnumerable<>, my custom PlatformObjectJsonConverter is executed in Write when return the result, which causes errors. I don't want my custom PlatformObjectJsonConverter should treat the IAsyncEnumerable as a value to serialize.

I tried to debug dotnet core should code and found out the reason is that because in SystemTextJsonOutputFormatter, the line if (declaredTypeJsonInfo.ShouldUseWith(runtimeType)) return false, which cause it try to serialize the result with object type in the closest code line await JsonSerializer.SerializeAsync(responseStream, context.Object, SerializerOptions, httpContext.RequestAborted);

Expected Behavior

I expect that my custom JsonConverter should not catch the result returned in api of type IAsyncEnumerable<> to help the api return the result as stream like default behavior

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

8

Anything else?

No response

captainsafia commented 6 months ago

@duc01226 Can you share a complete repro project for your scenario? I believe that the behavior you're seeing is technically correct given how you've defined the JsonConverter.

duc01226 commented 6 months ago

@duc01226 Can you share a complete repro project for your scenario? I believe that the behavior you're seeing is technically correct given how you've defined the JsonConverter.

This is my newly created repo to reproduce the errors. Thanks for your help. @captainsafia https://github.com/duc01226/DemoDotnet8BugJsonConvertOfObject/tree/main

duc01226 commented 6 months ago

Hi @captainsafia. Could you please help to take a look at this? I have debugged myself in dotnet core and I believe this is a bug.

I tried to debug the dotnet core should code and found out the reason is that in SystemTextJsonOutputFormatter, the line if (declaredTypeJsonInfo.ShouldUseWith(runtimeType)) return false, which causes it to try to serialize the result with object type in the closest code line await JsonSerializer.SerializeAsync(responseStream, context.Object, SerializerOptions, httpContext.RequestAborted);