sibartlett / Geo

A geospatial library for .NET
https://www.nuget.org/packages/Geo/
GNU Lesser General Public License v3.0
176 stars 39 forks source link

NativeAot compatibility #56

Open tipa opened 7 months ago

tipa commented 7 months ago

Due to the use of System.Xml.Serialization, this library isn't NativeAot-compatible.

using Geo.Gps.Serialization;

try
{
    var data = File.ReadAllBytes("path_to_gpx");
    using var stream = new MemoryStream(data);
    var streamWrapper = new StreamWrapper(stream);
    var gpsData = new Gpx10Serializer().CanDeSerialize(streamWrapper) ?
        new Gpx10Serializer().DeSerialize(streamWrapper) :
        new Gpx11Serializer().DeSerialize(streamWrapper);
}
catch (Exception e)
{
    Console.WriteLine(e);
}

dotnet publish .\geo_nativeaot\bin\Release\net8.0\win-x64\publish\geo_nativeaot.exe

GpxFile cannot be serialized because it does not have a parameterless constructor.
   at System.Xml.Serialization.TypeDesc.CheckSupported() + 0x42
   at System.Xml.Serialization.TypeScope.GetTypeDesc(Type, MemberInfo, Boolean, Boolean) + 0xbd
   at System.Xml.Serialization.ModelScope.GetTypeModel(Type, Boolean) + 0x5a
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type, XmlRootAttribute, String) + 0x50
   at System.Xml.Serialization.XmlSerializer.GetMapping() + 0x4f
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) + 0x98
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) + 0x209
   at Geo.Gps.Serialization.Xml.GpsXmlDeSerializer`1.DeSerialize(StreamWrapper) + 0xc7

When excluding the Geo assembly from trimming, another error surfaces:

<ItemGroup>
    <TrimmerRootAssembly Include="Geo" />
</ItemGroup>
System.InvalidOperationException: There is an error in XML document (3, 3).
 ---> System.NotSupportedException: 'System.Xml.Serialization.ReflectionXmlSerializationReaderHelper.GetSetMemberValueDelegateWithType[Geo.Gps.Serialization.Xml.Gpx.Gpx11.GpxMetadata,System.DateTime](System.Reflection.MemberInfo)' is missing native code. MethodInfo.MakeGenericMethod() is not compatible with AOT compilation. Inspect and fix AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
   at System.Reflection.Runtime.MethodInfos.RuntimeNamedMethodInfo`1.GetUncachedMethodInvoker(RuntimeTypeInfo[], MemberInfo) + 0x2f
...

Demo project: geo_nativeaot.zip

sibartlett commented 7 months ago

Hi @tipa,

Thank you for raising the issue… so that I can help better, what functionality do you require from Geo?

I think there’s either two paths I could take:

tipa commented 7 months ago

Hi @sibartlett,

thanks for your swift response.

Basically, my app reads gpx files, iterates over the Routes, Tracks & Waypoints properties of GpsData, collects all the "Coordinates" and displays them as paths and pins on a map view. I am not using the serialization parts of this library in my project.

I think System.Xml.Serialization is incompatible with NativeAot as it uses methods (like MethodInfo.MakeGenericMethod()) that use reflection. In another app of mine where I used System.Xml.Serialization I was able to work around this limitation by rewriting the deserialization code using System.Xml.Linq. I don't know if this is an option for this library and how much work this would involve.