-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Closed
Labels
📌 seQUESTeredIdentifies that an issue has been imported into Quest.Identifies that an issue has been imported into Quest.in-prThis issue will be closed (fixed) by an active pull request.This issue will be closed (fixed) by an active pull request.
Description
When using the JSON source generator with [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Seralization)], the JsonSerializer.SerializeAsync|Serialize methods that accept Stream and PipeWriter throw InvalidOperationException. This is not a regression from .NET 8.0 (when using a Stream).
var pipe = new Pipe();
await JsonSerializer.SerializeAsync(pipe.Writer, new JsonMessage { message = "Hello, World!" }, SerializationJsonContext.Default.JsonMessage);
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web, GenerationMode = JsonSourceGenerationMode.Serialization)]
[JsonSerializable(typeof(JsonMessage))]
partial class SerializationJsonContext : JsonSerializerContext
{
}
struct JsonMessage
{
public required string message { get; set; }
}Stack trace:
Unhandled exception. System.InvalidOperationException: TypeInfoResolver 'SerializationJsonContext' did not provide property metadata for type 'JsonMessage'.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_NoMetadataForTypeProperties(IJsonTypeInfoResolver resolver, Type type)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Converters.JsonMetadataServicesConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsync(PipeWriter pipeWriter, T rootValue, Int32 flushThreshold, CancellationToken cancellationToken, Object rootValueBoxed)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsync(PipeWriter pipeWriter, T rootValue, Int32 flushThreshold, CancellationToken cancellationToken, Object rootValueBoxed)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsync(PipeWriter pipeWriter, T rootValue, Int32 flushThreshold, CancellationToken cancellationToken, Object rootValueBoxed)
at Program.<Main>$(String[] args) in D:\src\local\JsonSerializeToPipe\JsonSerializeToPipe\Program.cs:line 20
at Program.<Main>(String[] args)
Full repro app that multi-targets net8.0 and net9.0 and shows serialization succeeding when using other overloads of Serialize or using a generated JsonSerializationContext with default generation mode:
using System.Text.Json.Serialization;
using System.Text.Json;
#if NET9_0_OR_GREATER
using System.IO.Pipelines;
#endif
var message = new JsonMessage { message = "Hello, World!" };
Console.WriteLine($"Serialize to string with {nameof(DefaultJsonContext)}: {JsonSerializer.Serialize(message, DefaultJsonContext.Default.JsonMessage)}");
Console.WriteLine($"Serialize to string with {nameof(SerializationJsonContext)}: {JsonSerializer.Serialize(message, SerializationJsonContext.Default.JsonMessage)}");
#if NET9_0_OR_GREATER
var pipe1 = new Pipe();
Console.Write($"Serialize to pipe with {nameof(DefaultJsonContext)}...");
await JsonSerializer.SerializeAsync(pipe1.Writer, new JsonMessage { message = "Hello, World!" }, DefaultJsonContext.Default.JsonMessage);
Console.WriteLine($"done!");
try
{
Console.Write($"Serialize to pipe with {nameof(SerializationJsonContext)}...");
var pipe2 = new Pipe();
await JsonSerializer.SerializeAsync(pipe2.Writer, new JsonMessage { message = "Hello, World!" }, SerializationJsonContext.Default.JsonMessage);
Console.WriteLine($"done!");
}
catch (Exception ex)
{
Console.WriteLine($"error!: {ex.GetType().Name} -> {ex.Message}");
}
#endif
using var ms1 = new MemoryStream();
Console.Write($"Serialize to stream (async) with {nameof(DefaultJsonContext)}...");
await JsonSerializer.SerializeAsync(ms1, new JsonMessage { message = "Hello, World!" }, DefaultJsonContext.Default.JsonMessage);
Console.WriteLine($"done!");
try
{
using var ms2 = new MemoryStream();
Console.Write($"Serialize to stream (async) with {nameof(SerializationJsonContext)}...");
await JsonSerializer.SerializeAsync(ms2, new JsonMessage { message = "Hello, World!" }, SerializationJsonContext.Default.JsonMessage);
Console.Write($"done!");
}
catch (Exception ex)
{
Console.WriteLine($"error!: {ex.GetType().Name} -> {ex.Message}");
}
using var ms3 = new MemoryStream();
Console.Write($"Serialize to stream (sync) with {nameof(DefaultJsonContext)}...");
JsonSerializer.Serialize(ms3, new JsonMessage { message = "Hello, World!" }, DefaultJsonContext.Default.JsonMessage);
Console.WriteLine($"done!");
try
{
using var ms4 = new MemoryStream();
Console.Write($"Serialize to stream (sync) with {nameof(SerializationJsonContext)}...");
JsonSerializer.Serialize(ms4, new JsonMessage { message = "Hello, World!" }, SerializationJsonContext.Default.JsonMessage);
Console.Write($"done!");
}
catch (Exception ex)
{
Console.WriteLine($"error!: {ex.GetType().Name} -> {ex.Message}");
}
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web, GenerationMode = JsonSourceGenerationMode.Default)]
[JsonSerializable(typeof(JsonMessage))]
partial class DefaultJsonContext : JsonSerializerContext
{
}
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web, GenerationMode = JsonSourceGenerationMode.Serialization)]
[JsonSerializable(typeof(JsonMessage))]
partial class SerializationJsonContext : JsonSerializerContext
{
}
struct JsonMessage
{
public required string message { get; set; }
}Output:
Serialize to string with DefaultJsonContext: {"message":"Hello, World!"}
Serialize to string with SerializationJsonContext: {"message":"Hello, World!"}
Serialize to pipe with DefaultJsonContext...done!
Serialize to pipe with SerializationJsonContext...error!: InvalidOperationException -> TypeInfoResolver 'SerializationJsonContext' did not provide property metadata for type 'JsonMessage'.
Serialize to stream (async) with DefaultJsonContext...done!
Serialize to stream (async) with SerializationJsonContext...error!: InvalidOperationException -> TypeInfoResolver 'SerializationJsonContext' did not provide property metadata for type 'JsonMessage'.
Serialize to stream (sync) with DefaultJsonContext...done!
Serialize to stream (sync) with SerializationJsonContext...error!: InvalidOperationException -> TypeInfoResolver 'SerializationJsonContext' did not provide property metadata for type 'JsonMessage'.
Metadata
Metadata
Assignees
Labels
📌 seQUESTeredIdentifies that an issue has been imported into Quest.Identifies that an issue has been imported into Quest.in-prThis issue will be closed (fixed) by an active pull request.This issue will be closed (fixed) by an active pull request.