ExtendedXmlSerializer/home

Sprache.ParseException for async lambda inside of a method

Closed this issue ยท 8 comments

I stumbled upon what appears to be a bug, that can be reproduced with the following code. I am using version 3.4.1 in a netcoreapp3.1 application:

static void Main(string[] args)
{
    new ConfigurationContainer().Create().Serialize(new Foo());
}

public class Foo
{
    public string Bar { get; set; }
}

public interface ISomething { }

public class Something : ISomething
{
    Func<ISomething, Task> Check<T>(Func<T, Task> data)
    {
        return async o => await data((T)o); // this causes it to bomb out
        return o => data((T)o); // this works without issue
    }
}

When the line

return async o => await data((T)o);

is used, the following error is generated:

Sprache.ParseException
  HResult=0x80131500
  Message=Parsing failure: unexpected '<'; expected letter (Line 1, Column 1); recently consumed: 
  Source=Sprache
  StackTrace:
   at Sprache.ParserExtensions.Parse[T](Parser`1 parser, String input)
   at ExtendedXmlSerializer.ContentModel.Reflection.TypeNameFormatter.Format(TypeInfo type)
   at ExtendedXmlSerializer.ContentModel.Reflection.TypeNameFormatter.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.Core.Sources.LinkedDecoratedSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.DecoratedSource`2.Get(TParameter parameter)
   at System.Linq.Lookup`2.Create(IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
   at System.Linq.Enumerable.ToLookup[TSource,TKey](IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
   at System.Linq.Enumerable.ToLookup[TSource,TKey](IEnumerable`1 source, Func`2 keySelector)
   at ExtendedXmlSerializer.ContentModel.Reflection.AssemblyTypePartitions.Format(IGrouping`2 grouping)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector)
   at ExtendedXmlSerializer.ContentModel.Reflection.AssemblyTypePartitions.Create(Assembly parameter)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
   at ExtendedXmlSerializer.ContentModel.Reflection.AssemblyTypePartitions.Get(TypePartition parameter)
   at ExtendedXmlSerializer.Core.Sources.FirstAssignedSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.ContentModel.Reflection.PartitionedTypeCandidates.Create(IIdentity parameter)
   at ExtendedXmlSerializer.Core.Sources.StructureCacheBase`2.CreateStructure(TKey parameter)
   at System.Runtime.CompilerServices.ConditionalWeakTable`2.GetValueLocked(TKey key, CreateValueCallback createValueCallback)
   at System.Runtime.CompilerServices.ConditionalWeakTable`2.GetValue(TKey key, CreateValueCallback createValueCallback)
   at ExtendedXmlSerializer.Core.Sources.StructureCacheBase`2.Get(TKey key)
   at ExtendedXmlSerializer.ContentModel.Reflection.TypeCandidates.Get(IIdentity parameter)
   at ExtendedXmlSerializer.ContentModel.Reflection.Types.Create(IIdentity parameter)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
   at ExtendedXmlSerializer.ContentModel.Members.MemberSerializers.IsMember(IMember profile)
   at ExtendedXmlSerializer.ContentModel.Members.MemberSerializers.Content(IMember profile, IMemberAccess access)
   at ExtendedXmlSerializer.ContentModel.Members.MemberSerializers.Property(IConverter converter, IMember profile, IMemberAccess access)
   at ExtendedXmlSerializer.ContentModel.Members.MemberSerializers.Get(IMember parameter)
   at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at ExtendedXmlSerializer.ContentModel.Members.MemberSerializations.Create(TypeInfo parameter)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
   at ExtendedXmlSerializer.ContentModel.Members.InstanceMemberSerialization..ctor(TypeInfo type, IMemberSerializations serializations)
   at ExtendedXmlSerializer.ContentModel.Members.InstanceMemberSerializations.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.ContentModel.Members.MemberedContents.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.Core.Sources.ConditionalSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.ContentModel.Content.RecursionAwareContents.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.ExtensionModel.Xml.CustomSerializationExtension.Contents.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.Core.Sources.Cache`2.Create(TKey parameter)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
   at ExtendedXmlSerializer.ExtensionModel.References.DeferredContents.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.ContentModel.Content.Serializers.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.Core.Sources.CoercedParameter`3.Get(TFrom parameter)
   at ExtendedXmlSerializer.Core.Sources.DelegatedSource`2.Get(TParameter parameter)
   at ExtendedXmlSerializer.ExtensionModel.References.ReferenceAwareSerializers.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.ContentModel.Content.DynamicAwareSerializers.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.ExtensionModel.RootInstanceExtension.Serializers.Get(TypeInfo parameter)
   at ExtendedXmlSerializer.Core.Sources.Cache`2.Create(TKey parameter)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at ExtendedXmlSerializer.Core.Sources.CacheBase`2.Get(TKey key)
   at ExtendedXmlSerializer.ExtensionMethodsForCoreSources.Get[T](IParameterizedSource`2 this, Type parameter)
   at ExtendedXmlSerializer.ExtensionModel.Xml.Write.Execute(Writing parameter)
   at ExtendedXmlSerializer.ExtensionModel.Xml.Serializer.Serialize(XmlWriter writer, Object instance)
   at ExtendedXmlSerializer.ExtensionModel.ThreadProtectionExtension.Serializer.Serialize(XmlWriter writer, Object instance)
   at ExtendedXmlSerializer.ExtensionModel.Xml.ExtendedXmlSerializer.Serialize(XmlWriter writer, Object instance)
   at ExtendedXmlSerializer.ExtensionModel.Xml.InstanceFormatter.Get(Object parameter)
   at ExtendedXmlSerializer.ExtensionMethodsForSerialization.Serialize(IExtendedXmlSerializer this, IXmlWriterFactory factory, Func`1 stream, Object instance)
   at ExtendedXmlSerializer.ExtensionMethodsForSerialization.Serialize(IExtendedXmlSerializer this, Object instance)
   at ExtendedXMLSerializer_Issue.Program.Main(String[] args) in C:\Users\woodrowp\Desktop\ExtendedXMLSerializer_Issue\Program.cs:line 19

The error is NOT thrown if the line is changed to:

return o => data((T)o);

Why is the serializer attempting to serialize a method of the class? I am not aware of any attributes that would allow the method to be ignored by the serializer.

The demo project for this is attached.

ExtendedXMLSerializer_Issue.zip

Issue Label Bot is not confident enough to auto-label this issue. See dashboard for more details.

Doh, @pmwoodrow thank you for writing in and reporting this. I can confirm that this occurs with a test that I have created using the code you have provided. It appears that we are running into a problem with the type resolution code on container startup/initialization. I agree that this seems odd and totally unexpected that it is throwing on a method. I will see if I can get this situated and fixed for you sometime this weekend. ๐Ÿ‘

FWIW it appears we can remove the interface and reduce it to the following:

		[Fact]
		public void Verify()
		{
			new ConfigurationContainer().Create().Serialize(new Foo());
		}

		public class Foo
		{
			public string Bar { get; set; }
		}

		public class Something
		{
			Func<object, Task> Check<T>(Func<T, Task> data)
			{
				return async o => await data((T)o); // this causes it to bomb out
			}
		}

@Mike-E-angelo, thanks for the quick response on this. I had a feeling that the interface was not important, given my testing identified the presence of the async/await to be the tipping point. I just wanted to make sure it was captured in the original post in case it had any bearing at all.

Alright @pmwoodrow looks like this is due to how the asynchronous state machine componentry is generated. We were already doing a check for the CompilerGeneratedAttribute but apparently this is not applied to the asynchronous bits when it is generated by the compiler. ๐Ÿคทโ€โ™‚๏ธ

So now we do a further, subsequent check for "unspeakable" types.

A build is here for you to check out and verify if it works better for your solution:
#471 (comment)

If this works well for you, we will deploy this to NuGet on Tuesday. โœ”

@Mike-E-angelo, thanks for the quick turn on a dev build. I can confirm that it resolves the issue in my application that was exhibiting issues with previous builds. Looks good to deploy to NuGet.

Alrighty, this has been deployed to NuGet:
https://www.nuget.org/packages/ExtendedXmlSerializer/

Please do let me know if you encounter any issues with this build and I will take a look into it for you. Thank you for improving ExtendedXmlSerializer! Closing for now.

An extensible Xml Serializer for .NET that builds on the functionality of the classic XmlSerializer with a powerful and robust extension model.