Skip to content

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

Closed
@ivanpovazan

Description

@ivanpovazan

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>

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions