SpanJson icon indicating copy to clipboard operation
SpanJson copied to clipboard

Error when serializing IAsyncEnumerable in .NET 6

Open silkfire opened this issue 4 years ago • 7 comments

I've had a piece of code that serializes an IAsyncEnumerable since this type was introduced in .NET Core 3.1 and it's been working great together with SpanJson.

Recently, I upgraded to the newly released .NET 6 and after testing my application I got a long stack of errors at the location that serializes this type.

Would you mind checking what's causing the issue?

ArgumentException: Type 'System.Runtime.InteropServices.StructLayoutAttribute' does not have a default constructor (Parameter 'type')
System.Linq.Expressions.Expression.New(Type type)
SpanJson.Formatters.ComplexFormatter.BuildDeserializeDelegate<T, TSymbol, TResolver>()
SpanJson.Formatters.ComplexClassFormatter<T, TSymbol, TResolver>..cctor()

System.RuntimeFieldHandle.GetValue(RtFieldInfo field, object instance, RuntimeType fieldType, RuntimeType declaringType, ref bool domainInitialized)
System.Reflection.RtFieldInfo.GetValue(object obj)
SpanJson.Resolvers.ResolverBase.GetDefaultOrCreate(Type type)
SpanJson.Resolvers.ResolverBase<TSymbol, TResolver>.BuildFormatter(Type type)
SpanJson.Resolvers.ResolverBase<TSymbol, TResolver>.<GetFormatter>b__3_0(Type x)
System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>.GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
SpanJson.Resolvers.ResolverBase<TSymbol, TResolver>.GetFormatter(Type type)
SpanJson.Resolvers.ResolverBase<TSymbol, TResolver>.GetFormatter(JsonMemberInfo memberInfo, Type overrideMemberType)
SpanJson.Formatters.ComplexFormatter.BuildSerializeDelegate<T, TSymbol, TResolver>()
SpanJson.Formatters.ComplexClassFormatter<T, TSymbol, TResolver>..cctor()

(The chain of errors is much longer than this but looks very similar to above)

silkfire avatar Nov 16 '21 22:11 silkfire

Honestly I'm surprised that IAsyncEnumerable works at all.

Tornhoof avatar Nov 17 '21 21:11 Tornhoof

Oh, why is that?

A clarification, this was actually the return type of an action in ASP.NET Core. It used to serialize it as a regular IEnumerable<>, but doesn't work in .NET 6.

silkfire avatar Nov 17 '21 21:11 silkfire

IAsnycEnumerable only works properly if you have a full async pipeline. I guess that in 5.0 it was actually sync or fully synchronously buffered and in 6.0 it's not anymore.

Tornhoof avatar Nov 17 '21 22:11 Tornhoof

Okay, I see then. I converted it to a Task<ActionResult<IEnumerable<>>> to make it work. The error occurs when SpanJson is scanning and reflecting the controller actions to determine how to serialize each respective response.

silkfire avatar Nov 17 '21 22:11 silkfire

It would be quite useful if you could provide a repro for your problem, this problem is likely dependent on one of the concrete types.

Tornhoof avatar Nov 17 '21 22:11 Tornhoof

Just create an ASP.NET Core project with a controller containing an action with the return type IAsyncEnumerable<> targeting .NET 6, and you should hit the error as soon as you launch the app.

silkfire avatar Nov 17 '21 22:11 silkfire

Okay, you still return IAsnycEnumerable, I was confused as you wrote about Ienumerable in between. As I previously said, this can't work properly.

Tornhoof avatar Nov 17 '21 22:11 Tornhoof