graphql-dotnet / graphql-dotnet/graphql-client
Json Serialiser doesn't handle structs well and ignores type converters
- Dominant language
- C#
- Stars
- 648
- Forks
- 136
- PR merge metrics
- No merged PRs in 30d
Description
Hello,
I have some wrapper types that I want to use with GraphQL, which look like this:
```csharp
public struct ProductId(Guid value) {
public Guid Value => value;
public override string ToString() => value.ToString();
public override bool Equals(object? obj) => obj is ProductId other && other.Value == value;
public override int GetHashCode() => value.GetHashCode();
public static bool operator ==(ProductId left, ProductId right) => left.Value == right.Value;
public static bool operator !=(ProductId left, ProductId right) => !(left == right);
}
```
I also provide `JsonConverters` for these types, which look similar to:
```csharp
class ProductIdSystemTextJsonConverter : JsonConverter
{
public override ProductId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
new Foo(Guid.Parse(reader.GetString()!));
public override void Write(Utf8JsonWriter writer, ProductId value, JsonSerializerOptions options) =>
writer.WriteStringValue(value.Value);
}
```
I register the converters in the client:
```csharp
var serialiser = new SystemTextJsonSerializer
{
Options =
{
PropertyNameCaseInsensitive = true
}
};
serialiser.Options.Converter.Add(new ProductIdTypeConverter());
```
But when deserialising the GraphQL response I get this error:
```
System.InvalidOperationException
Sequence contains no matching element
at System.Linq.ThrowHelper.ThrowNoMatchException()
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
at GraphQL.Client.Serializer.SystemTextJson.ImmutableConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options) in /_/src/GraphQL.Client.Serializer.SystemTextJson/ImmutableConverter.cs:line 80
```
I do not quite understand why `ImmutableConverter` was chosen and not the specific one that I registered...
I validated the approach, and it works if I create my wrapper types as `record`s somehow:
```csharp
public readonly record struct ProductId(Guid Value)
{
public override string ToString() => Value.ToString();
}
```
But the goal is to make it work with plain structs and have libraries like https://github.com/lucasteles/Strongly to generate wrapper types, Json converters, and all the required boilerplate around them.
I believe that fixing the "plain structs" misbehavior would allow it to work rather smoothly.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.