Bug 19750 - DataContractSerializer does not handle XmlElement property correctly
Summary: DataContractSerializer does not handle XmlElement property correctly
Status: CONFIRMED
Alias: None
Product: Class Libraries
Classification: Mono
Component: WCF assemblies (show other bugs)
Version: 3.2.x
Hardware: PC Windows
: Normal normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2014-05-14 00:08 UTC by jackjoy
Modified: 2014-06-15 04:42 UTC (History)
5 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description jackjoy 2014-05-14 00:08:15 UTC
DataContractSerializer does not handling XmlElement in the same behavior with .NET Framework.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Reflection;
using System.Runtime.Serialization;

namespace DataContractSerializerTest
{
    [DataContract(Namespace = "http://www.test.org")]
    public class TestConfiguration
    {
        private string m_applicationName;
        private XmlElement m_extension;


        /// <summary>
        /// A descriptive name for the the application (not necessarily unique).
        /// </summary>
        /// <value>The name of the application.</value>
        [DataMember(IsRequired = true, EmitDefaultValue = false, Order = 0)]
        public string ApplicationName
        {
            get { return m_applicationName; }
            set { m_applicationName = value; }
        }

        /// <summary>
        /// A bucket to store additional application specific configuration data.
        /// </summary>
        /// <value>The extensions.</value>
        [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 1)]
        public XmlElement Extension
        {
            get { return m_extension; }
            set { m_extension = value; }
        }

        public void UpdateExtension(object extension)
        {
            if (extension == null)
            {
                this.Extension = null;
                return;
            }

            var settings = new XmlWriterSettings();
            settings.Encoding = Encoding.UTF8;
            settings.Indent = true;
            settings.CloseOutput = false;
            StringBuilder buffer = new StringBuilder();
            using (var writer = XmlDictionaryWriter.Create(buffer, settings))
            {
                var serializer = new DataContractSerializer(extension.GetType());
                serializer.WriteObject(writer, extension);
            }

            XmlDocument document = new XmlDocument();
            document.InnerXml = buffer.ToString();
            this.Extension = document.DocumentElement;
        }

        public T ParseExtension<T>()
        {
            if (this.Extension == null)
                return default(T);

            using (var reader = new XmlNodeReader(this.Extension))
            {
                var serializer = new DataContractSerializer(typeof(T));
                return (T)serializer.ReadObject(reader, false);
            }
        }


        public void Save(string filePath)
        {
            Stream ostrm = File.Open(filePath, FileMode.Create, FileAccess.ReadWrite);

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Encoding = System.Text.Encoding.UTF8;
            settings.Indent = true;
            settings.CloseOutput = true;

            XmlWriter writer = XmlDictionaryWriter.Create(ostrm, settings);
            try
            {
                DataContractSerializer serializer = new DataContractSerializer(GetType());
                serializer.WriteObject(writer, this);
            }
            finally
            {
                writer.Close();
            }
        }


        public static TestConfiguration Load(string filePath)
        {
            using (XmlTextReader reader = new XmlTextReader(File.OpenRead(filePath)))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof(TestConfiguration));
                return serializer.ReadObject(reader, false) as TestConfiguration;
            }
        }

    }

    [DataContract(Namespace = "http://www.test.org")]
    public class ExtensionConfiguration
    {
        private string m_userName;

        [DataMember(IsRequired = true, EmitDefaultValue = false, Order = 0)]
        public string UserName
        {
            get { return m_userName; }
            set { m_userName = value; }
        }
    }

    public static class Test
    {
        public static void DoWork()
        {
            try
            {
                var ec = new ExtensionConfiguration();
                ec.UserName = "Anonymous";

                var tc = new TestConfiguration();
                tc.ApplicationName = "Test Application";
                tc.UpdateExtension(ec);

                // determine file path
                var assembly = Assembly.GetExecutingAssembly();
                var assemblyPath = new Uri(assembly.CodeBase).LocalPath;
                var assemblyDir = Path.GetDirectoryName(assemblyPath);
                var filePath = Path.Combine(assemblyDir, "test.xml");

                // save to file
                tc.Save(filePath);

                // load from file
                var ntc = TestConfiguration.Load(filePath);
                if (ntc == null || ntc.ApplicationName != tc.ApplicationName)
                {
                    throw new InvalidOperationException("Test failed of TestConfiguration!");
                }

                // parse extension configuration
                var nec = ntc.ParseExtension<ExtensionConfiguration>();
                if (nec == null || nec.UserName != ec.UserName)
                {
                    throw new InvalidOperationException("Test failed of ExtensionConfiguration!");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

    }
}

The generated "test.xml" is:

<?xml version="1.0" encoding="utf-8"?>
<TestConfiguration xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.test.org">
  <ApplicationName>Test Application</ApplicationName>
  <Extension>
    <ExtensionConfiguration xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.test.org">
      <UserName>Anonymous</UserName>
    </ExtensionConfiguration>
  </Extension>
</TestConfiguration>

Test.DoWork() will run OK in .net framework.But will throw exception in Mono for Android:
System.ArgumentException: Data contract member UserName for the type DataContractSerializerTest.ExtensionConfiguration is required, but missing in the input XML.

The main difference between .NET Framework and Mono for Android is the deserialized "Extension" property.Mono for Android add an external layer.

* In .NET Framework,ntc.Extension.OuterXml is :
<ExtensionConfiguration xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.test.org">
   <UserName>Anonymous</UserName>
</ExtensionConfiguration>

* In Mono for Android,ntc.Extension.OuterXml is :
<Extension>
    <ExtensionConfiguration xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.test.org">
      <UserName>Anonymous</UserName>
    </ExtensionConfiguration>
</Extension>

We encountered this bug when porting code from .net framework to Mono for Android.
Comment 1 Ram Chandra 2014-05-14 07:30:49 UTC
I tried this issue and I am able to reproduce this and here are my observations.

Steps to reproduce
1. Open "Android Application" in Xamarin Studio
2. Create an new class with the name of "TestConfiguration.cs" 
3. Copy and paste the code mentioned in bug description.
4. Set default .NET Runtime (Tools=>options=> .Net Runtimes=> Microsoft.Net(Default).
5. Call the "DoWork()" method of "Test" class.

I observed that when set the default runtime "Microsoft.Net" and call the "DoWork()" method, it throws and exception i.e. 
     "Data contract member UserName for the type
      DataContractSerializerTest.ExtensionConfiguration is required, but missing in
      the input XML."
 but when I click on the "Show Details" link on the exception dialog, it show "error dialog" and when I click on "details" it shows the "System.ArgumentException: Illegal characters in path".  
I have also find that the "test.xml" is not generated for me.

I also observed that when I change the default runtime to "mono 3.3.0", I am getting build error i.e.

 "Build failed. Could not find type 'System.Globalization.SortVersion'.
  Build: 1 error, 0 warnings".

Screencast: http://www.screencast.com/t/MePlelNQOad
IDE logs: https://gist.github.com/saurabh360/efcbc97bc69d5b6c6db3

Please let me know if I am missing anything?

Environment Info:

Xamarin Studio
Version 4.2.5 (build 0)
Installation UUID: 851620d2-e950-4682-b459-991ccec9d895
Runtime:
 Microsoft .NET 4.0.30319.18408
 GTK+ 2.24.22 (MS-Windows theme)
 GTK# 2.12.25

Xamarin.Android
Version: 4.12.4 (Business Edition)
Android SDK: D:\SDK\AndroidSDK
 Supported Android versions:
  2.1   (API level 7)
  2.2   (API level 8)
  2.3   (API level 10)
  3.1   (API level 12)
  3.2   (API level 13)
  4.0   (API level 14)
  4.0.3 (API level 15)
  4.1   (API level 16)
  4.2   (API level 17)
  4.3   (API level 18)
  4.4   (API level 19)
Java SDK: C:\Program Files (x86)\Java\jdk1.6.0_31
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) Client VM (build 20.6-b01, mixed mode, sharing)

Build Information
Release ID: 402050000
Git revision: 95ac543f224a70960a9ab71e24ce341eb87de06f
Build date: 2014-05-02 12:59:15-04
Xamarin addins: b81285ac0156281956135adb96685f98922893a1

Operating System
Windows 6.1.7601.65536 (64-bit)
Comment 3 Jonathan Pryor 2014-05-14 09:50:59 UTC
This is a Mono BCL bug. Take the sample code provided in Comment #0, and rename Test.DoWork() to Test.Main(), then:

    $ mcs test.cs -r:System.Runtime.Serialization.dll
    $ mono test.exe
> Unhandled Exception:
> System.ArgumentException: Data contract member UserName for the type DataContractSerializerTest.ExtensionConfiguration is required, but missing in the input XML.
>   at System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer, System.String id, Boolean empty) [0x00000] in <filename unknown>:0 
>   at System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer, System.String id) [0x00000] in <filename unknown>:0 
>   at System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer) [0x00000] in <filename unknown>:0 
>   at System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
>   at System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
>   at System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Xml.XmlReader reader, System.Type declaredType, System.Runtime.Serialization.KnownTypeCollection knownTypes, IDataContractSurrogate surrogate, System.Runtime.Serialization.DataContractResolver resolver, System.Runtime.Serialization.DataContractResolver defaultResolver, System.String name, System.String ns, Boolean verifyObjectName) [0x00000] in <filename unknown>:0 
>   at System.Runtime.Serialization.DataContractSerializer.ReadObject (System.Xml.XmlDictionaryReader reader, Boolean verifyObjectName) [0x00000] in <filename unknown>:0 
>   at System.Runtime.Serialization.DataContractSerializer.ReadObject (System.Xml.XmlReader reader, Boolean verifyObjectName) [0x00000] in <filename unknown>:0 
>   at DataContractSerializerTest.TestConfiguration.ParseExtension[ExtensionConfiguration] () [0x00000] in <filename unknown>:0 
>   at DataContractSerializerTest.Test.Main () [0x00000] in <filename unknown>:0
Comment 4 jameswilddev 2014-06-06 09:39:07 UTC
Just encountered this issue myself, commenting to get on the CC list as I can't see a way to do it otherwise.
Comment 5 jameswilddev 2014-06-15 04:42:16 UTC
https://bitbucket.org/jameswilddev/sunruse.vectors/branch/Mono-bug-19750
Here's my repro of the issue; set the configuration to NUnit to build under Xamarin Studio, run tests.  A few fail because Mono and Microsoft don't agree on the message for an ArgumentNullException, but most of the MeshDeserialization* tests fail due to this bug.  Re-run on Visual Studio in the Debug configuration (switches you over to MSTEST) and all tests pass.

Xamarin Studio 5.0.1 on Windows 8.1 Update 1 64-bit.  According to the build options, I'm on Mono Runtime 3.3.0. (6cd4ddc)

Note You need to log in before you can comment on or make changes to this bug.