Closed
Description
Description
Hello, friends!
I'm having an issue with JSON deserialization (serialization is working).
- If I try to deserialize an item at a time, it works (so that deserialization for the PaymentType works);
- If I try to deserialize the array (no matter if targeting a HashSet, List, Array, it will fail with that error above);
- I've tried to use a custom JsonConverter to deserialize the whole collection, but that didn't work too.
The code:
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(StableCoins), nameof(StableCoins))]
[JsonDerivedType(typeof(CryptoCurrency), nameof(CryptoCurrency))]
public abstract record PaymentType
{
public sealed record StableCoins : PaymentType
{
public static readonly StableCoins Instance = new();
}
public sealed record CryptoCurrency(CryptoCurrencyId Id) : PaymentType;
}
// related classes
public readonly record struct CryptoCurrencyId(Guid Value) : IEntityId<CryptoCurrencyId>
{
public static CryptoCurrencyId From(Guid value) => new(value);
public static implicit operator Guid(CryptoCurrencyId id) => id.Value;
public static implicit operator CryptoCurrencyId(Guid value) => new(value);
}
public sealed class EntityIdJsonConverter<T> : JsonConverter<T>
where T : struct, IEntityId<T>
{
public override T Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options
)
{
var value = reader.GetString();
var guid = string.IsNullOrEmpty(value) ? Guid.Empty : Guid.Parse(value);
return T.From(guid);
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.Value);
}
}
[JsonSourceGenerationOptions(
JsonSerializerDefaults.Web,
UseStringEnumConverter = true,
RespectNullableAnnotations = true,
PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace,
Converters = [typeof(EntityIdJsonConverter<CryptoCurrencyId>)]
)]
[JsonSerializable(typeof(PaymentType))]
[JsonSerializable(typeof(HashSet<PaymentType>))]
public partial class DbJsonSerializerContext : JsonSerializerContext;
Reproduction Steps
Just try to deserialize the string with or without a JsonSerializerContext.
The test code (XUnit + Shoudly):
public class DatabaseSerializationTests
{
[Fact]
public void DeserializeHashSetOfPaymentTypes()
{
var json = """
[{"type": "StableCoins"}, {"id": "01975718-8994-7a90-a305-629d9954912d", "type": "CryptoCurrency"}, {"id": "01975718-8994-785d-8d10-509c194c264f", "type": "CryptoCurrency"}, {"id": "01975718-8994-78eb-bee4-3aae93166b33", "type": "CryptoCurrency"}]
""";
var paymentTypes = JsonSerializer.Deserialize(json, DbJsonSerializerContext.Default.HashSetPaymentType);
paymentTypes.ShouldNotBeNull();
}
}
Expected behavior
I expect to receive a hash set of instances of payment types.
Actual behavior
I'm receiving the following error.
System.NotSupportedException
The JSON payload for polymorphic interface or abstract type 'Sentrafi.Payments.PaymentType' must specify a type discriminator. Path: $[1] | LineNumber: 0 | BytePositionInLine: 32.
at System.Text.Json.ThrowHelper.ThrowNotSupportedException(ReadStack& state, Utf8JsonReader& reader, Exception innerException)
at System.Text.Json.ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(JsonTypeInfo typeInfo, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, T& value, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Deserialize(Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo`1 jsonTypeInfo, Nullable`1 actualByteCount)
at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo`1 jsonTypeInfo)
at Sentrafi.Tests.Server.Infrastructure.Persistence.DatabaseSerializationTests.DeserializeHashSetOfPaymentTypes() in /Users/danfma/Develop/Sentrafi/sentrafi-server/Sentrafi.Tests/Server/Infrastructure/Persistence/DatabaseSerializationTests.cs:line 17
Regression?
Apparently, not. I've tried with .NET 8 and .NET 10, and the behavior remains the same.
Known Workarounds
None so far.
Configuration
- .NET Version: .NET 10 preview 5 (but the project is built with .NET 9)
- OS: MacOS Sequoia 15.5
- Architecture: ARM64
- I've used polymorphism in the same project with other objects and it works;
- No Blazor, deserialization on the server.
Other information
No response