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:
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
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:
Tagging subscribers to 'os-ios': @vitek-karas, @kotlarmilos, @ivanpovazan, @steveisok, @akoeplinger
See info in area-owners.md if you want to be subscribed.
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:This was reported to us by a customer who experienced the problem when targeting iOS platforms with .NET as the
DynamicCodeSupport
feature switch isfalse
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 tofalse
.Repro
If we consider the following example:
and build/run it as a console application with
dotnet run
, the output is as follows:When we rebuild and rerun the application with
DynamicCodeSupport
set to false ie:dotnet run -p:DynamicCodeSupport=false
the app throws with:Additional notes
This is probably similar issue to https://github.com/dotnet/runtime/issues/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 withDynamicCodeSupport=false
.Known workarounds when targeting iOS platforms
Enable interpreter by adding the following in the project file: