-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON deserialization fails in iOS release build if class implements an interface #75802
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsDescriptionA simple JSON deserialization using The same app works in Debug build in the iOS simulator as expected. Reproduction Steps
During startup, run this code:
Full project file:
Expected behaviorThe app starts successfully and manages to de-serialize the JSON regardless of whether the class implements an interface or not. Note that removing the interface Actual behaviorJSON deserialization fails with this exception:
Regression?The same code works in Xamarin.iOS. Known WorkaroundsNo response Configuration.NET 6.0.4.1 Other informationNo response
|
Are you certain this is a bug in .Net? Seems like it's a Newtonsoft issue. If so, the bug should be filed in that repo. |
@gregsdennis It works just fine in |
Understood, but it might be that the package just needs handle a special case in this OS. There is the possibility that the issue is the package. |
Unlikely, the same code works with Xamarin.iOS. |
@markuspalme could it be the linker stripping out stuff? Could you try add |
@Cheesebaron Thanks for the suggestion, on iOS that is not an option though: |
Tagging subscribers to 'os-ios': @steveisok, @akoeplinger Issue DetailsDescriptionA simple JSON deserialization using The same app works in Debug build in the iOS simulator as expected. Reproduction Steps
During startup, run this code:
Full project file:
Expected behaviorThe app starts successfully and manages to de-serialize the JSON regardless of whether the class implements an interface or not. Note that removing the interface will make the de-serialization work as expected. Actual behaviorJSON deserialization fails with this exception:
Regression?The same code works in Xamarin.iOS. Known WorkaroundsNo response Configuration.NET 6.0.401 Other informationNo response
|
I have tried
|
Here's a small self-contained example: |
Adding |
@markuspalme UseInterpreter is not for Release builds, Apple won't allow that. |
@Cheesebaron Yes, I figured but wanted to share that it helps here - maybe it helps pinpointing the root cause. |
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsDescriptionA simple JSON deserialization using The same app works in Debug build in the iOS simulator as expected. Reproduction Steps
Full project file:
Self-contained example project: Expected behaviorThe app starts successfully and manages to de-serialize the JSON regardless of whether the class implements an interface or not. Note that removing the interface will make the de-serialization work as expected. Actual behaviorJSON deserialization fails with this exception:
Regression?The same code works in Xamarin.iOS. Known WorkaroundsNo response Configuration.NET 6.0.401 Other informationNo response
|
@jeffschwMSFT I don't believe the issue is related to System.Text.Json. I removed the label but wasn't sure what the appropriate area label should be. Perhaps @steveisok or @akoeplinger know. |
System.Text.Json should be the right area label. Source generators are the only 100% reliable way to perform Json serialization/deserialization in the presence of trimming or AOT compilation without fallbacks. Unfortunately, trim warnings that would notify about this problem are disabled for iOS apps by default. You can set This is duplicate #74141 and number of other similar issues. @eiriktsarpalis My suggestion would be:
|
The OP concerns Json.NET (Newtonsoft) serialization issues in iOS. I agree that it falls under the same category as #74141, but I wonder what our approach should be when users report trimming-related failures when using third party reflection-based libraries. We might want to consider asking them to file an issue with said third-party libraries asking about AOT support.
It is, although the wording is certainly more understated than that. |
@jkotas I will try to enable the trim warnings. JSON is at the heart of many apps and this feels like a regression coming from Xamarin.iOS where such scenarios worked out of the box. Migrating to |
@markuspalme I'm not sure if and when Json.NET plans on bringing AOT support, but you might want to consider opening an issue in its own repo or those of the other libraries that depend on it. In the meantime, migrating to System.Text.Json source generation is probably the only viable option. |
@eiriktsarpalis Thanks for your input. Given that earlier versions of Xamarin.iOS supported this scenario out of the box even in AOT mode, this seems like a bad surprise or even a blocker for anyone porting applications to |
@eiriktsarpalis So my understanding is that this problem here is caused by trimming. To preserve all the types in my code, I have added this to the project file as described here (https://devblogs.microsoft.com/dotnet/customizing-trimming-in-net-core-5/):
The
The de-serialization does not work with that in place. Shouldn't this ensure that all my types are preserved and available through reflection? The whole story around trimming and linking is rather intimidating:
Is there any guidance available on which one to use when and how they work together? |
@sbomer here you go: Build command: |
@sbomer Did the binlog reveal anything interesting? |
@sbomer if you need to bounce ideas off of someone who has ios set up, please let me know. |
Sorry for the delay - I wasn't able to see anything wrong from the binlog, which indicates that the descriptor is getting passed along correctly. @vitek-karas would your repro tool help here to collect the input assemblies? |
@markuspalme would you be able to try this tool by @vitek-karas to see if you can obtain a repro? https://github.com/vitek-karas/illinkrepro You'll need to clone it on the machine where you ran the publish command and obtained the binlog. Then inside of the cloned directory, do |
Thanks @markuspalme, that gets us a bit further. I was able to tweak the repro as I described here to get some linker output. I was hoping that the linker output would show something obviously wrong, but I didn't notice anything. I see that Would you also be able to share your publish output (ideally both with and without the descriptor) so I can compare? If that doesn't show what's wrong I will probably need to set up an iOS development environment to debug (or debug it with @steveisok). |
@sbomer Here are the IPA files: With descriptor: Without descriptor: There is is at least a difference in size: |
Thanks @markuspalme, in the output you shared I noticed that the I am not seeing the same thing in any of my repros so far. I also got your original repro to run on a simulator, but didn't see the issue there either. Now I'm trying to get set up with a provisioning profile with some help from @steveisok. Thanks for your patience. |
@sbomer I saw the same but was not sure it's relevant because I don't know if the assembly is used for anything but metadata in the AOT build. The error is not reproducible on the simulator. I do think it's an AOT issue and not a trimming issue for this reason - but I have no idea how to investigate any further by myself. |
So far I tend to agree that it doesn't look like a linker issue. I think we need someone more familiar with the AOT/Xamarin scenarios to investigate. /cc @steveisok |
Looks like the assembly has been ran through ILStrip after trimming. ILStrip builds on top of some unserviced version of Cecil. Is there a way to disable it to get it out of the picture? I can't figure out which targets enable it, but the methods are marked noininling and the bodies are just a I saw some hints in the .targets I found that ILStrip might be disabled if interpreter is enabled and we've established that enabling interpreted fixes it here #75802 (comment) so this might be ILStrip. |
Cc @akoeplinger for ILStrip |
@MichalStrehovsky @markuspalme you can try setting |
@MichalStrehovsky I did that. The assembly is now intact: But the error still occurs on device. As far as I know, the IL is used for metadata only with AOT enabled which is probably why method bodies are stripped away to save space. |
@MichalStrehovsky Is there anything else I can help with analyzing this issue? |
@MichalStrehovsky @steveisok @sbomer Could this be related to #69410? |
Can still be reproduced with .NET 7. |
following |
@akoeplinger please investigate if this is indeed an ILStrip issue. |
@akoeplinger do you the recent ILStrip changes might have fixed this? Can you please validate? |
This is fixed in 8.0.100-preview.7.23376.3, presumably by #69410. |
Description
A simple JSON deserialization using
Newtonsoft.Json
fails on iOS in a release build as soon as the class that is trying be be de-serialized implements an interface.The same app works in Debug build in the iOS simulator as expected.
Reproduction Steps
Create a new iOS app with
dotnet new ios
Set a valid bundle identifier that allows installing the app on a physical device
Add this code to the project:
During startup, run this code:
Build the app for a device:
dotnet publish testapp.csproj -f:net6.0-ios -c:Release /p:CodesignKey="Apple Development: ******" /p:CodesignProvision="Test app" /p:ArchiveOnBuild=true -r ios-arm64 --self-contained
Deploy to device and run
Full project file:
Self-contained example project:
https://github.com/markuspalme/dotnetruntime-75802
Expected behavior
The app starts successfully and manages to de-serialize the JSON regardless of whether the class implements an interface or not.
Note that removing the interface will make the de-serialization work as expected.
Actual behavior
JSON deserialization fails with this exception:
Error setting value to 'Id' on 'testapp.ProductImage'.
Regression?
The same code works in Xamarin.iOS.
Known Workarounds
No response
Configuration
.NET 6.0.401
iOS 16, same on 15.6.1
Other information
No response
The text was updated successfully, but these errors were encountered: