-
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
RuntimeInstanceNotAllowed Error Initializing XmlSerializer on Android Release Build in .NET 9 #109724
Comments
I don't believe your issue is related to the MAUI UI framework, it's a runtime one: Between 8.0 and 9.0, a switch was added (#100416 and #105766) to throw on these values. Most likely what's tripping it up on Release mode is trimming (which would explain it working in Debug mode, and not Release.) I'm not sure how to specifically handle trimming with XmlSerializer, @jonathanpeppers would you know of what to do here? |
@LakshanF @sbomer - this is due to the addition of |
Minimal repro: using System.Xml.Serialization;
using System.ComponentModel;
var s = new XmlSerializer(typeof(C));
_ = new C().T; // Prevent C.T from being removed by trimming
public class C {
[DefaultValue(typeof(C), "c")]
public Type T { get; }
} <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
</Project> This is currently by design - the ctor of Note that in this example the use of It's possible to disable the throwing behavior by setting
Is it correct that the app was working in Debug mode? These settings should result in the same behavior whether you're in Debug or Release mode, so that might be a bug. |
Yes, the app works in Debug mode but I thought the code would not be trimmed in a debug build. I'm not aware of any trim warnings in the repro I provided, and I typically treat warnings as errors, so while it is possible I missed one it seems unlikely. On the face of it, if I think what you've written means that to operate in a supported configuration I must eliminate uses of |
@jonathanpeppers I'm aware that we made some changes to the trimming defaults for android recently - are both Debug and Release builds getting the defaults set by the illink targets? As far as I understand, android doesn't show trim warnings unless using
Instances of |
Given that I need to serialize and deserialize XML and tell the XML serializer not to serialize some properties if they have their default value, it seems like my only option is to use Does that seem like it would work (albeit at the cost of a larger compiled app) and is there some other method that I'm missing to achieve the same XML serialization behavior? I checked and |
That may work (I'm not sure how well supported it is to disable trimming entirely in an android app) - but it sounds like you are mainly interested in compat with the .NET 8 behavior, so I would recommend setting |
I'm mainly interested in the ability to omit default valued items from XML serialization, I'd prefer it be done as it was in .NET 8 just because that's less work for me, but if there's a preferred method, I can probably convert to using that. I'd shied away from That means I have a workaround for my instance of the problem but there remains a situation where code that worked fine on NET 8 receives no warnings and appears to work fine on NET 9, right up until you try an Android release build, then it fails. I'd suggest at the very least a warning, so users who may fall afoul of this get a hint that all may not be well. |
So as to detour a problem with XmlSerializr (see dotnet/runtime#109724)
We are definitely planning to fix the apparent breaking change between 8 and 9 - thanks a lot for spotting this and filing an issue! Note that the partial trim mode which is the default for MAUI apps doesn't make hard guarantees about trim compatibility. It tends to work in most cases, but there's definitely ways where you can get it to break. That has been like that since a long time ago (goes back to Xamarin). The full trim mode on the other hand does make guarantees, but it also produces lot of trim related warnings. If there are warnings, the app may break. If there are no warnings it will work (if not, it's a bug). In .NET 9 we've made lot of improvements to MAUI to make at least the core of MAUI trim compatible, so that a simple app in MAUI doesn't produce any warnings and thus can work with full trimming. Larger apps tend to depend on lot of additional components all of which need to be compatible with trimming for this to work - getting the ecosystem adapted to trimming is a long journey though. |
@matouskozak could you please look into preparing a fix for the breaking change? In short - we should set |
You are welcome @vitek-karas, and thanks for the explanation, which clarifies things for me, While I was happy to have a workaround that was simple to apply (thanks again @sbomer), a supported fix is preferable. |
Well, the fix is very likely going to be basically the workaround, just done for you... but I agree it should be done. |
I'd pretty much expected that, the key is, it'll be a supported configuration, so thanks. |
So as to detour a problem with XmlSerializr (see dotnet/runtime#109724)
Putting an update on the fix:
|
That surprises me - we should make sure to understand this. I don't think |
…=partial` (#9525) Context: dotnet/runtime#109724 In .NET 9, certain apps could crash with: System.ArgumentException: RuntimeInstanceNotAllowed ?, in object DefaultValueAttribute.get_Value() ?, in new XmlAttributes(ICustomAttributeProvider) ?, in XmlAttributes XmlReflectionImporter.GetAttributes(MemberInfo) ?, in bool XmlReflectionImporter.InitializeStructMembers(StructMapping, StructModel, bool, string, RecursionLimiter) ?, in StructMapping XmlReflectionImporter.ImportStructLikeMapping(StructModel, string, bool, XmlAttributes, RecursionLimiter) .NET's concept of `$(PublishTrimmed)` is used to decide which trimmer feature switches are toggled. This is normally set for both Debug & Release, but Android only sets it for Release. This means that the `$(_DefaultValueAttributeSupport)` feature switch is not set properly in some cases, which causes the crash. For now, we can set `$(_DefaultValueAttributeSupport)` for `TrimMode=partial`, the default in .NET MAUI apps. See #9526 for how we might better address this in the future. In order to test this change: * Add a `XmlSerializerTest` to `Mono.Android-Tests` * Run a copy of `Mono.Android-Tests` with `-p:TestsFlavor=TrimModePartial` * Also set `$(_DefaultValueAttributeSupport)` for `TrimMode=full` in our test project, so `XmlSerializerTest` will pass in that mode as well. Co-authored-by: Jonathan Peppers <[email protected]>
…=partial` (#9525) Context: dotnet/runtime#109724 In .NET 9, certain apps could crash with: System.ArgumentException: RuntimeInstanceNotAllowed ?, in object DefaultValueAttribute.get_Value() ?, in new XmlAttributes(ICustomAttributeProvider) ?, in XmlAttributes XmlReflectionImporter.GetAttributes(MemberInfo) ?, in bool XmlReflectionImporter.InitializeStructMembers(StructMapping, StructModel, bool, string, RecursionLimiter) ?, in StructMapping XmlReflectionImporter.ImportStructLikeMapping(StructModel, string, bool, XmlAttributes, RecursionLimiter) .NET's concept of `$(PublishTrimmed)` is used to decide which trimmer feature switches are toggled. This is normally set for both Debug & Release, but Android only sets it for Release. This means that the `$(_DefaultValueAttributeSupport)` feature switch is not set properly in some cases, which causes the crash. For now, we can set `$(_DefaultValueAttributeSupport)` for `TrimMode=partial`, the default in .NET MAUI apps. See #9526 for how we might better address this in the future. In order to test this change: * Add a `XmlSerializerTest` to `Mono.Android-Tests` * Run a copy of `Mono.Android-Tests` with `-p:TestsFlavor=TrimModePartial` * Also set `$(_DefaultValueAttributeSupport)` for `TrimMode=full` in our test project, so `XmlSerializerTest` will pass in that mode as well. Co-authored-by: Jonathan Peppers <[email protected]>
Putting additional update as I continue investigating:
Note: the android fix got merged and will be part of .NET 9 servicing (dotnet/android@20f08bd). I'll keep this issue open to continue investigating the iOS case. |
Update on the iOS investigation. I believe the XMLSeriliazer behavior is related to By default, At the moment I'm unsure why runtime/src/libraries/System.Private.CoreLib/src/System/ComponentModel/DefaultValueAttribute.cs Line 29 in 462630b
Not sure if this is intended behavior @sbomer but at least we don't need any fix for iOS currently. |
Did you mean to link a different issue?
That is expected - the code is shared with coreclr's corelib where the default must be true for un-trimmed apps, and we rely on the setting being passed at publish time to disable the feature.
Agreed, I would expect the trimming settings from https://github.com/dotnet/runtime/blob/f9c86dc7b449bbdfd2fcafa58e513357372509a5/src/tools/illink/src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets#L34-L61 to kick in and disable to kick in. |
Yes, my bad. #107252
cc: @rolfbjarne do you happen to know why the trimming settings from the linked |
Do you have a binlog I can look at? |
Actually I think I know the difference: we set which is after you check for PublishTrimmed to set the defaults: The reason for this is that when building on Windows, and the build is not connected to a Mac (i.e. using Hot Restart), we can't run ILLink (one reason being that the custom linker steps only works on macOS) - but connecting to a Mac is done in a target, so we only know if we're connected to a Mac or not later in the build. You could probably confirm this by setting PublishTrimmed=true in your csproj, which should reproduce the Android behavior. Ideally (from our point of view at least!) you'd set the trimmer defaults in a public target, which we could make our "_ComputePublishTrimmed" target depend on. It's not the first time this problem with default values being out of sync comes up, we have a rather big list of copied defaults which I'd love to be able to get rid of: |
Thank you Rolf. I can confirm that the issue also reproduces when you set manually To reproduce the crash on iOS you need to:
or
|
Thanks @rolfbjarne and @matouskozak for the investigation.
Ah, right, I remember this coming up before. We need to set the defaults early enough for them to flow to RuntimeHostConfigurationOption, which is currently computed during evaluation: https://github.com/dotnet/sdk/blob/20ba0c29c5be4ebc4d14b453c0efc743a43bf277/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets#L515-L520. Setting these early usually ensures that they flow into the build (not just publish). Our thinking is that PublishTrimmed signals intent to trim during build, as well as actually trimming during publish.
Just to make sure I understand - is the idea that the dependency would be conditioned on the computed value of PublishTrimmed? From our point of view I think we want to encourage folks to set PublishTrimmed early - see what we are recommending for Android: dotnet/android#9526. Could iOS use a similar approach (set PublishTrimmed even for the Windows build, and use some other mechanism to prevent running ILLink)? cc @vitek-karas for opinions. |
I think we should try to change the behavior to set I do agree that we need a different mechanism to suppress running As described above, the meaning of
|
Description
App fails with an exception in a release build of .NET 9 (.NET 8 and debug builds of .NET 9 work fine).
It looks like the fault happened because of a call on
new XmlSerializer(typeof(Meal))
(deferring that call defers the fault).The abbreviated stack trace looks like this:
Steps to Reproduce
class-constructor-fault
branch.dotnet restore
5.Then
6.Press the left arrow to see:
If it were working correctlyyou would see:
Then
Link to public reproduction project repository
https://github.com/david-maw/DivisiBill.git
Version with bug
9.0.0-rc.2.24503.2
Is this a regression from previous behavior?
Yes, this used to work in .NET MAUI
Last version that worked well
8.0.93 SR9.3
Affected platforms
Android
Affected platform versions
Android 14
Did you find any workaround?
No response
Relevant log output
The text was updated successfully, but these errors were encountered: