dotnet / runtimelab

This repo is for experimentation and exploring new ideas that may or may not make it into the main dotnet/runtime repo.
MIT License
1.42k stars 198 forks source link

[Native-AOT] Using Json Serialize and Deserialize with Native AOT? #635

Closed unofficialdev closed 3 years ago

unofficialdev commented 3 years ago

I am trying to use Json Serialize and Deserialize with Native AOT. I tried with System.Text.Json and NewtonSoft.Json, after compiling, my application couldn't launch. I know this is an old problem. I want to ask now is there any alternative to be able to read/write json? Any sample code with an alternative is appreciated (ex: JsonCodeGen tutorial or document). I cannot find the documentation or sample code related to this problem. Thanks for any solution

MichalStrehovsky commented 3 years ago

Both System.Text.Json and Newtonsoft.Json can be made to work, but you need to write RD.XML. See docs for https://github.com/dotnet/runtimelab/blob/feature/NativeAOT/docs/using-nativeaot/debugging.md and https://github.com/dotnet/runtimelab/blob/feature/NativeAOT/docs/using-nativeaot/rd-xml-format.md.

Utf8json (with pre code generation enabled) provides the best experience with no RD.XML needed: https://github.com/neuecc/Utf8Json/#pre-code-generationunityxamarin-supports

unofficialdev commented 3 years ago

Thanks for your time

darkguy2008 commented 2 years ago

@MichalStrehovsky Hi! First of all thanks for your valuable work with NativeAOT and I'm happy to know it's made into the official runtimelab repo!

I have a question though, you seem to know in more detail how to make System.Text.Json and Newtonsoft.Json work with rd.xml. Unfortunately, there isn't much info about it online and everything around is just mostly vague (like, go reat those docs) which I've been through the entire weekend without much idea on how to fix the AOT warnings.

Maybe you can help by providing a real-world example on how to make those work with rd.xml as you say? I'm facing the same problem as @unofficialdev. Thanks!

jkotas commented 2 years ago

System.Text.Json source generator is the best way to make System.Text.Json work with NativeAOT: https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-source-generation . It should not require any rd.xml.

A real-world example for System.Text.Json source generation with NativeAOT is in the TechEmpower benchmarks: https://github.com/TechEmpower/FrameworkBenchmarks/blob/12b43943c669f86eaf4e571e8f5b3bd0ae35ac90/frameworks/CSharp/aspnetcore-corert/PlatformBenchmarks/BenchmarkApplication.cs#L39-L47

darkguy2008 commented 2 years ago

System.Text.Json source generator is the best way to make System.Text.Json work with NativeAOT: https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-source-generation . It should not require any rd.xml.

A real-world example for System.Text.Json source generation with NativeAOT is in the TechEmpower benchmarks: https://github.com/TechEmpower/FrameworkBenchmarks/blob/12b43943c669f86eaf4e571e8f5b3bd0ae35ac90/frameworks/CSharp/aspnetcore-corert/PlatformBenchmarks/BenchmarkApplication.cs#L39-L47

Hey @jkotas thanks for your answer! Yeah I just discovered that tonight, took me quite some effort as I didn't really want to create extra classes for all my models just to use the source generator, but I took the plunge and did it tonight. So far no rd.xml is required, although there's still a couple warnings around:

/_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/GenericMethodHolder.cs(31): AOT analysis warning IL3050: System.Text.Json.Serialization.Metadata.GenericMethodHolder.CreateHolder(Type): Using member 'System.Type.MakeGenericType(Type[])' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. The native code for this instantiation might not be available at runtime. 
/_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverterFactory.cs(50): AOT analysis warning IL3050: System.Text.Json.Serialization.Converters.NullableConverterFactory.GetNullableConverterType(Type): Using member 'System.Type.MakeGenericType(Type[])' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. The native code for this instantiation might not be available at runtime. 

Could these be solved? And if so, how?

Also, maybe unrelated, but if I disable reflection by using <IlcDisableReflection>true</IlcDisableReflection> it works (with the same warnings) but it crashes when attempting to deserialize a class (even with the code generator!), just like Nick John explains here (there's a sample repo there): https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/#comment-9820 so I guess it's not 100% reflection-free?

As for the real-world example, thanks! That repo seems useful not only as a System.Text.Json example but for other AOT-related things as well :)

jkotas commented 2 years ago

Could these be solved? And if so, how?

I have opened https://github.com/dotnet/runtime/issues/63843 . Let's continue the discussion there. I do not think you can really solve it. It is a problem for System.Text.Json source generators to address.

disable reflection by using true

IlcDisableReflection mode is very restrictive. It disables majority of the reflection APIs, even the ones that are generally ok with AOT. We do not plan support it in its current form.

For the particular case you have hit, it is using reflection here: https://github.com/dotnet/runtime/blob/b9be49411073bb85cc86f8cb92d452f8881dfe7d/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs#L23. This use of reflection should be easy to fix (add internal virtual property that is overriden for all internal converters), but there are very likely other issues.