Bug 12571

Summary: Usage of XElement with XmlAnyElementAttribute is not supported by XmlSerializer
Product: [Mono] Class Libraries Reporter: Luciano <l.martorella>
Component: System.XMLAssignee: Marek Safar <masafa>
Severity: normal CC: adrian.murphy, allie.miller, kumpera, miguel, mono-bugs+mono, pj.beaman, stefan
Priority: Normal    
Version: master   
Target Milestone: Untriaged   
Hardware: All   
OS: All   
Tags: Is this bug a regression?: ---
Last known good build:
Attachments: CmdLine sample to replicate the crash

Description Luciano 2013-06-06 04:05:03 UTC
Created attachment 4080 [details]
CmdLine sample to replicate the crash

Using XElement (from System.Xml.Linq) instead of XmlElement as a field/property causes an InvalidCastException when deserializing the class using the XmlSerializer:

   public XElement MyAnyData;  // instead of XmlElement

.The NET Framework 3.5/4.0 allows to use XElement in place of XmlElement not requiring any cast or additional code.

Mono 2.8 and 3.0.10 are crashing instead, trying to internally cast XmlElement to XElement instead. 
This shows that actually the XElement is partially supported by XmlElement; but it is however failing to transfer the read XML data to an XElement instance.

Please find the attached small command-line based solution that replicates the wrong behavior in few lines. Using Xamarin Studio it is possible to run the sample and to quickly switch from .NET Framework to Mono to compare the wrong behavior with the expected one.

I've tested the application on Windows, but mono will crash on Xamarin Android too.

The usage of LINQ classes instead of System.Xml ones is offering so many advantage to justify this issue to be fixed soon.

Thank you,
Comment 1 Luciano 2013-06-06 04:09:34 UTC
Full exception stack:

Unhandled Exception: System.ArgumentException: Object type System.Xml.XmlElement cannot be converted to target type: System.Xml.Linq.XElement
Parameter name: val  at System.Reflection.MonoField.SetValue (System.Object obj, System.Object val, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Globalization.CultureInfo culture) [0x000e3] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\corlib\System.Reflection\MonoField.cs:158
  at System.Reflection.FieldInfo.SetValue (System.Object obj, System.Object value) [0x00000] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\corlib\System.Reflection\FieldInfo.cs:139
  at System.Xml.Serialization.XmlTypeMapMember.SetValue (System.Object ob, System.Object value) [0x00045] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\System.XML\System.Xml.Serialization\XmlTypeMapMember.cs:103
  at System.Xml.Serialization.XmlSerializationReaderInterpreter.SetMemberValue (System.Xml.Serialization.XmlTypeMapMember member, System.Object ob, System.Object value, Boolean isValueList) [0x0001a] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\System.XML\System.Xml.Serialization\XmlSerializationReaderInterpreter.cs:583
  at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadMembers (System.Xml.Serialization.ClassMap map, System.Object ob, Boolean isValueList, Boolean readBySoapOrder) [0x00903] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\System.XML\System.Xml.Serialization\XmlSerializationReaderInterpreter.cs:478
  at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstanceMembers (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob) [0x00000] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\System.XML\System.Xml.Serialization\XmlSerializationReaderInterpreter.cs:240
  at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadClassInstance (System.Xml.Serialization.XmlTypeMapping typeMap, Boolean isNullable, BooleancheckType) [0x000df] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\System.XML\System.Xml.Serialization\XmlSerializationReaderInterpreter.cs:230
  at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadObject (System.Xml.Serialization.XmlTypeMapping typeMap, Boolean isNullable, Boolean checkType) [0x00031] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\System.XML\System.Xml.Serialization\XmlSerializationReaderInterpreter.cs:193
  at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadRoot (System.Xml.Serialization.XmlTypeMapping rootMap) [0x00057] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\System.XML\System.Xml.Serialization\XmlSerializationReaderInterpreter.cs:184
  at System.Xml.Serialization.XmlSerializationReaderInterpreter.ReadRoot () [0x00028] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\System.XML\System.Xml.Serialization\XmlSerializationReaderInterpreter.cs:87  at System.Xml.Serialization.XmlSerializer.Deserialize (System.Xml.Serialization.XmlSerializationReader reader) [0x0001c] in C:\cygwin\tmp\monobuild\build\BUILD\mono-2.10.9\mcs\class\System.XML\System.Xml.Serialization\XmlSerializer.cs:361
Comment 3 Rodrigo Kumpera 2013-06-17 13:01:26 UTC
Marek, could you take a look at this one?
Comment 4 Luciano 2014-01-27 09:10:24 UTC
Unfortunately this bug prevents to use PCL assemblies on a mono/Xamarin environment.
PCL subsets only allow the LINQ XElement (or even System.Object) to be used as class member, the underlying type XmlElement is pruned away in all PCL Profiles.

If we wants to use PCL for common shared assemblies no workarounds seems to be possible. Even trying to force Object as underlying type for a XmlAnyElement decorated member, the resulting type would always be an XmlElement instance, inaccessible from PCL.

A feasible fix is to allow the System.Xml.Linq assembly to inject some conversion code from XmlElement to XElement type.
Please find attached a proposed patch.
(However with this simple fix the developer should force the execution of the XElement.cctor() before being able to deserialize the sample class in the example. A valid CLR module initializers or some custom AppDomain hook should be implemented to make the sample working without any other workaround).

Thank you,
Comment 6 Martin Baulig 2014-02-25 13:02:50 UTC
Fixed; mono/master 2d573ae.
Comment 7 PJ 2014-04-03 12:50:37 UTC
This fix is in the mono-3.4.0-branch, and has been released to the Alpha channel with Mono 3.4.0 (d4511ef).
Comment 8 Luciano 2014-10-27 12:09:40 UTC
Unfortunately I need to reopen the issue.
Even if the case of single XElement is now fixed, I've just realized that the case of XElement[] is still not supported.

So basically, the same original project will still crash with this simple change:

   public XElement[] MyAnyData;  // instead of XmlElement[]

Naturally .NET supports that behavior. Mono still crashes, but XmlElement[] is supported.

Tested with mono 3.10.0 (Xamarin iOS).

Thank you,
Comment 9 Stefan de Vogelaere 2016-03-22 12:04:37 UTC
Any news on this issue? This is so old!
I also have the same issue as stated in last comment!
Comment 10 Marek Safar 2016-11-10 17:47:18 UTC
Fixed in master and C9 branch