Bug 21073 - missing namespace specifiers from xamarin datacontral serializer and wrong order for derived class fields
Summary: missing namespace specifiers from xamarin datacontral serializer and wrong or...
Status: NEW
Alias: None
Product: Class Libraries
Classification: Mono
Component: WCF assemblies (show other bugs)
Version: unspecified
Hardware: PC Windows
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2014-07-03 02:50 UTC by Chris Turner
Modified: 2014-07-08 18:57 UTC (History)
1 user (show)

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

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report for Bug 21073 on GitHub or Developer Community if you have new information to add and do not yet see a matching new report.

If the latest results still closely match this report, you can use the original description:

  • Export the original title and description: GitHub Markdown or Developer Community HTML
  • Copy the title and description into the new report. Adjust them to be up-to-date if needed.
  • Add your new information.

In special cases on GitHub you might also want the comments: GitHub Markdown with public comments

Related Links:
Status:
NEW

Description Chris Turner 2014-07-03 02:50:13 UTC
.net 4 datacontractserializer seems to alphabetically order the serialized fields based on the original class, so if you serialize a derived class, it will order the fields for the parent class, and then order the fields for the derived class.

ultimately we are trying to serialize a class on an android tablet and have it deserialized with the default datacontractserializer on the server that is already in production. It works windows to server, not android/ios to server.

Parent class stuff: (original version 1 type)
  [Serializable]
    public enum PortalDeviceType
    {
        None,
        iOS,
        Android,
        WindowsPhone,
        Windows
    };

    [Serializable]
    [Flags()]
    public enum PortalNotifications
    {
        None = 0,
        TardyAlerts = 0x10,
        IncidentAlerts = 0x20,
        All = 0xffff,
        UseCurrent = 0x10000
    };

    // we encode the string if its binary so it goes over the wire nicely..
    [Serializable]
    public class DeviceForNotification
    {
        public PortalDeviceType DeviceType = PortalDeviceType.None;

        public PortalNotifications NotificationsType = PortalNotifications.None;

        public string DeviceID = string.Empty;

        public string Name = string.Empty;

        public bool DevelopmentBuild = false;
    }


version 2 type (derived class)

  [Serializable]
    public class DeviceForNotification2 : PSRMWebService.Model.Version1.DeviceForNotification
    {
        // version2 data
        public string OsVersion = string.Empty;
        public string DeviceModel = string.Empty;
        public string ScreenSize = string.Empty;
        public string Date = string.Empty;

        // used to upgrade.
        // 0 == Urbanairship push
        // 1 == Parse.push
        public int Version = 0;
    }


running on windows using the datacontractserializer:
<DeviceForNotification2 xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version2" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<DevelopmentBuild xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">true</DevelopmentBuild>
<DeviceID xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">04a86b07-55bb-4157-b970-15f0f4985e6f</DeviceID>
<DeviceType xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">Android</DeviceType>
<Name xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">Test Device</Name>
<NotificationsType xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">All</NotificationsType>
<Date>2014-07-03T06:10:13.0457859Z</Date>
<DeviceModel>Asus Nexus 7</DeviceModel>
<OsVersion>Most likely windows</OsVersion>
<ScreenSize>1920x1280d4</ScreenSize>
<Version>0</Version>
</DeviceForNotification2>

note: the field order is per type, not global.

now the data generated from the android app 
<DeviceForNotification2 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version2">
<Date>2014-07-03T06:39:11.9370340Z</Date>
<DevelopmentBuild xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">true</DevelopmentBuild>
<DeviceID xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">bea8f240-e9e7-4e13-a9c7-bada2cbe99fc</DeviceID>
<DeviceModel>Asus Nexus 7</DeviceModel>
<DeviceType xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">Android</DeviceType>
<Name xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">google</Name>
<NotificationsType xmlns="http://schemas.datacontract.org/2004/07/PSRMWebService.Model.Version1">None</NotificationsType>
<OsVersion>REL [Kitkat]</OsVersion>
<ScreenSize>1200x1824d2</ScreenSize>
<Version>0</Version>
</DeviceForNotification2>

note these are ordered based on the derived type, not the two types (parent, derived)
This second data packet generated on android will not deserialize on the server (Windows server 2012, .net 4)

the android and the windows test app use the following to generate the serialization

    protected void SerializeToString(object Data, Type DataType, out int DataLength, out string DataString)
        {
            DataLength = 0;
            using (var MS = new MemoryStream())
            {
                // default text encoding is UTF-8 apparently
                DataContractSerializer ser = new DataContractSerializer(DataType);
                ser.WriteObject(MS, Data);

		byte[] Buffer = MS.ToArray();
		long Length = Buffer.LongLength;

		// the length parameter is becuase the buffer is a set size...
                DataString = Encoding.UTF8.GetString( Buffer, 0, (int) Length );

		// this looks hokey, it is, the datacontractserlializer is supposed to default to utf-8 but
		// some builds of monotuch it puts a double byte mark at the start. so we remove it otherwise
		// it wont deseaerlize
		if ( (int) DataString[0] > 65000 )
		{
			DataString = DataString.Substring( 1 );
		}
		DataLength = DataString.Length;
            }
        }
Comment 1 Chris Turner 2014-07-08 18:57:25 UTC
I have verified that if you reorder the fields generated by the mono datacontractserializer to the .net ordering (each type are ordered alphbetically in the hierarchical instead of alphbetical overall).

Then the .net datacontract serializer will deserialize things properly.