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)

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


Attachments

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.

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