Skip to content
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

XmlSerializer does not respect member type specified in XmlElement attribute when DynamicCodeSupport is false #108432

Open
ivanpovazan opened this issue Oct 1, 2024 · 2 comments
Milestone

Comments

@ivanpovazan
Copy link
Member

ivanpovazan commented Oct 1, 2024

Description

When there are multiple XmlElement attributes attached to a property, and one of them specifies that the member type is of some base type A, serializing an object whose property is initialized with type B, where B : A, throws with:

Unhandled exception. System.InvalidOperationException: There was an error generating the XML document.
 ---> System.InvalidOperationException: The type B was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

This was reported to us by a customer who experienced the problem when targeting iOS platforms with .NET as the DynamicCodeSupport feature switch is false by default on these platforms on all supported runtimes: NativeAOT and MonoAOT.

For reference, I created a console app reproduction which shows that this only happens when DynamicCodeSupport is set to false.

Repro

If we consider the following example:

using System.Xml.Serialization;

var container = new Container
{
    Items = new()
    {
        new B()
    }
};

XmlSerializer serializer = new XmlSerializer(typeof(Container));
using (StringWriter writer = new StringWriter())
{
    serializer.Serialize(writer, container);
    string xmlString = writer.ToString();
    Console.WriteLine(xmlString);
}

[XmlInclude(typeof(B))]
public class A { }
public class B : A { }
public class C { }

public class Container
{
    [XmlElement("As", typeof(A))]
    [XmlElement("Cs", typeof(C))]
    public List<object> Items { get; set; }
}

and build/run it as a console application with dotnet run , the output is as follows:

<?xml version="1.0" encoding="utf-16"?>
<Container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <As xsi:type="B" />
</Container>

When we rebuild and rerun the application with DynamicCodeSupport set to false ie: dotnet run -p:DynamicCodeSupport=false the app throws with:

Unhandled exception. System.InvalidOperationException: There was an error generating the XML document.
 ---> System.InvalidOperationException: The type B was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
   at System.Xml.Serialization.ReflectionXmlSerializationWriter.WriteElements(Object o, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, Boolean writeAccessors, Boolean isNullable)
   at System.Xml.Serialization.ReflectionXmlSerializationWriter.WriteArrayItems(ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, Object o)
   at System.Xml.Serialization.ReflectionXmlSerializationWriter.WriteStructMethod(StructMapping mapping, String n, String ns, Object o, Boolean isNullable, Boolean needType)
   at System.Xml.Serialization.ReflectionXmlSerializationWriter.WriteElements(Object o, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, Boolean writeAccessors, Boolean isNullable)
   at System.Xml.Serialization.ReflectionXmlSerializationWriter.GenerateTypeElement(Object o, XmlTypeMapping xmlMapping)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at Program.<Main>$(String[] args) in /Users/ivan/tmp/net8/MultipleXmlElementsWithDerivedTypes/Program.cs:line 14

Additional notes

This is probably similar issue to #107252 where we use ReflectionOnly serialization.

FWIW, when we keep only one XmlElement attribute (relevant for the test case) attached to the property, serialization works fine even with DynamicCodeSupport=false.

public class Container
{
    [XmlElement("As", typeof(A))]
-    [XmlElement("Cs", typeof(C))]
    public List<object> Items { get; set; }
}

Known workarounds when targeting iOS platforms

Enable interpreter by adding the following in the project file:

<UseInterpreter>true</UseInterpreter>
@ivanpovazan ivanpovazan added this to the 10.0.0 milestone Oct 1, 2024
Copy link
Contributor

Tagging subscribers to 'os-ios': @vitek-karas, @kotlarmilos, @ivanpovazan, @steveisok, @akoeplinger
See info in area-owners.md if you want to be subscribed.

@arlm
Copy link

arlm commented Oct 7, 2024

Hello @ivanpovazan

I have added you to a private project reproducing all the options you have suggested so that you can run the same way I am doing (there are scripts for running on device and on simulator).

Baseline is:

Project DynamicCodeSupport=true DynamicCodeSupport=false UseInterpreter=true UseInterpreter=false
issue-107252 works bug appears works works
issue-108432 works bug appears works works
XmlSerializationSample on Device bug appears bug appears bug appears bug appears
XmlSerializationSample on Simulator works bug appears bug appears bug appears

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants