简体   繁体   中英

Output of DataContractSerializer differs between .NET and Mono

I am serializing data in a Mono For Android application and sending it using REST to a .NET server listening using WCF. So far this has worked fine, however, with this particular data contract, although the server throws no errors, the Lists inside the data contract show up as empty.

Using Fiddler and creating two projects with the same code, I was able to compare the normal .NET DataContractSerializer output with the output from Mono's implementation of DataContractSerializer.

.NET output:

<VisitDataContractEx xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/Organization.Project.DataContracts">
  <_isDirty xmlns="http://schemas.datacontract.org/2004/07/Organization.DataContracts">true</_isDirty>
  <_id xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.Domain" xmlns="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:internalValue>a7b97b48-d3a9-419d-9f4e-330ffc7a01ee</d2p1:internalValue>
  </_id>
  <_key xmlns="http://schemas.datacontract.org/2004/07/Organization.DataContracts">false</_key>
  <_keyIdentifier xmlns="http://schemas.datacontract.org/2004/07/Organization.DataContracts">SurrogateKey</_keyIdentifier>
  <ChecklistComplete>false</ChecklistComplete>
  <Date>2013-03-05T15:43:49.5008406+02:00</Date>
  <GpsAccuracy>1</GpsAccuracy>
  <GpsLatitude>1</GpsLatitude>
  <GpsLongitude>1</GpsLongitude>
  <OrderComplete>false</OrderComplete>
  <PhotoComplete>false</PhotoComplete>
  <StockComplete>false</StockComplete>
  <Sync>2013-03-05T15:43:49.5468406+02:00</Sync>
  <checkListAnswers xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_list>
      <d2p1:IdentityDataReferenceOfCheckListAnswerDataContractExX8I0_S_SPU>
        <d2p1:_dataContract z:Id="i2">
          <d2p1:_isDirty>true</d2p1:_isDirty>
          <d2p1:_id xmlns:d6p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
            <d6p1:internalValue>95ae919b-a389-4ea7-a009-af1b91890c36</d6p1:internalValue>
          </d2p1:_id>
          <d2p1:_key>false</d2p1:_key>
          <d2p1:_keyIdentifier>SurrogateKey</d2p1:_keyIdentifier>
          <Answer>false</Answer>
          <checkListQuestion>
            <d2p1:_dataContract i:nil="true" />
            <d2p1:_description i:nil="true" />
            <d2p1:_hasDataContract>false</d2p1:_hasDataContract>
            <d2p1:_id xmlns:d7p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
              <d7p1:internalValue>176cbb31-7df2-4966-baa9-4e3cd2a0c6d5</d7p1:internalValue>
            </d2p1:_id>
          </checkListQuestion>
        </d2p1:_dataContract>
        <d2p1:_description i:nil="true" />
        <d2p1:_hasDataContract>true</d2p1:_hasDataContract>
        <d2p1:_id xmlns:d5p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
          <d5p1:internalValue>95ae919b-a389-4ea7-a009-af1b91890c36</d5p1:internalValue>
        </d2p1:_id>
      </d2p1:IdentityDataReferenceOfCheckListAnswerDataContractExX8I0_S_SPU>
    </d2p1:_list>
  </checkListAnswers>
  <comments xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_list />
  </comments>
  <directSalesAgent xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_dataContract i:nil="true" />
    <d2p1:_description i:nil="true" />
    <d2p1:_hasDataContract>false</d2p1:_hasDataContract>
    <d2p1:_id xmlns:d3p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
      <d3p1:internalValue>6f99f86a-5b1b-4f73-bdc3-388e0b7cf417</d3p1:internalValue>
    </d2p1:_id>
  </directSalesAgent>
  <directSalesAgentSuperVisor xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_dataContract i:nil="true" />
    <d2p1:_description i:nil="true" />
    <d2p1:_hasDataContract>false</d2p1:_hasDataContract>
    <d2p1:_id xmlns:d3p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
      <d3p1:internalValue>d57db20d-9b3a-4345-849e-d5a0d0d88f70</d3p1:internalValue>
    </d2p1:_id>
  </directSalesAgentSuperVisor>
  <photos xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_list>
      <d2p1:IdentityDataReferenceOfPhotoDataContractExX8I0_S_SPU>
        <d2p1:_dataContract z:Id="i3">
          <d2p1:_isDirty>true</d2p1:_isDirty>
          <d2p1:_id xmlns:d6p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
            <d6p1:internalValue>3db431e9-3338-4c96-aea9-d833eb0dc8ae</d6p1:internalValue>
          </d2p1:_id>
          <d2p1:_key>false</d2p1:_key>
          <d2p1:_keyIdentifier>SurrogateKey</d2p1:_keyIdentifier>
          <Content i:nil="true" />
          <Taken>2013-03-05T15:43:49.4748406+02:00</Taken>
        </d2p1:_dataContract>
        <d2p1:_description i:nil="true" />
        <d2p1:_hasDataContract>true</d2p1:_hasDataContract>
        <d2p1:_id xmlns:d5p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
          <d5p1:internalValue>3db431e9-3338-4c96-aea9-d833eb0dc8ae</d5p1:internalValue>
        </d2p1:_id>
      </d2p1:IdentityDataReferenceOfPhotoDataContractExX8I0_S_SPU>
    </d2p1:_list>
  </photos>
  <salesPoint xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_dataContract i:nil="true" />
    <d2p1:_description i:nil="true" />
    <d2p1:_hasDataContract>false</d2p1:_hasDataContract>
    <d2p1:_id xmlns:d3p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
      <d3p1:internalValue>692a294a-2d1b-4026-9693-0c0ce552a2fb</d3p1:internalValue>
    </d2p1:_id>
  </salesPoint>
  <stockCounts xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts" i:nil="true" />
</VisitDataContractEx>

Mono Output:

<VisitDataContractEx xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/Organization.Project.DataContracts">
  <_isDirty xmlns="http://schemas.datacontract.org/2004/07/Organization.DataContracts">true</_isDirty>
  <_id xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.Domain" xmlns="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:internalValue>9297eea9-82af-4981-ab9d-40aa0ac0fa0d</d2p1:internalValue>
  </_id>
  <_key xmlns="http://schemas.datacontract.org/2004/07/Organization.DataContracts">false</_key>
  <_keyIdentifier xmlns="http://schemas.datacontract.org/2004/07/Organization.DataContracts">SurrogateKey</_keyIdentifier>
  <ChecklistComplete>false</ChecklistComplete>
  <Date>2013-03-05T17:49:06.362243+02:00</Date>
  <GpsAccuracy>1</GpsAccuracy>
  <GpsLatitude>1</GpsLatitude>
  <GpsLongitude>1</GpsLongitude>
  <OrderComplete>false</OrderComplete>
  <PhotoComplete>false</PhotoComplete>
  <StockComplete>false</StockComplete>
  <Sync>2013-03-05T17:49:06.438934+02:00</Sync>
  <checkListAnswers xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_list>
      <d2p1:IdentityDataReferenceOfCheckListAnswerDataContractEx>
        <d2p1:_dataContract xmlns:d5p1="http://schemas.datacontract.org/2004/07/Organization.Project.DataContracts" z:Id="i2">
          <d2p1:_isDirty>true</d2p1:_isDirty>
          <d2p1:_id xmlns:d6p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
            <d6p1:internalValue>75083457-9714-4971-b60c-f28fa43167ad</d6p1:internalValue>
          </d2p1:_id>
          <d2p1:_key>false</d2p1:_key>
          <d2p1:_keyIdentifier>SurrogateKey</d2p1:_keyIdentifier>
          <Answer>false</Answer>
          <checkListQuestion xmlns:d6p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
            <d6p1:_dataContract xmlns:d7p1="http://schemas.datacontract.org/2004/07/Organization.Project.DataContracts" i:nil="true" />
            <d6p1:_description i:nil="true" />
            <d6p1:_hasDataContract>false</d6p1:_hasDataContract>
            <d6p1:_id xmlns:d7p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
              <d7p1:internalValue>176cbb31-7df2-4966-baa9-4e3cd2a0c6d5</d7p1:internalValue>
            </d6p1:_id>
          </checkListQuestion>
        </d2p1:_dataContract>
        <d2p1:_description i:nil="true" />
        <d2p1:_hasDataContract>true</d2p1:_hasDataContract>
        <d2p1:_id xmlns:d5p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
          <d5p1:internalValue>75083457-9714-4971-b60c-f28fa43167ad</d5p1:internalValue>
        </d2p1:_id>
      </d2p1:IdentityDataReferenceOfCheckListAnswerDataContractEx>
    </d2p1:_list>
  </checkListAnswers>
  <comments xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_list />
  </comments>
  <directSalesAgent xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_dataContract xmlns:d3p1="http://schemas.datacontract.org/2004/07/Organization.Project.DataContracts" i:nil="true" />
    <d2p1:_description i:nil="true" />
    <d2p1:_hasDataContract>false</d2p1:_hasDataContract>
    <d2p1:_id xmlns:d3p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
      <d3p1:internalValue>6f99f86a-5b1b-4f73-bdc3-388e0b7cf417</d3p1:internalValue>
    </d2p1:_id>
  </directSalesAgent>
  <directSalesAgentSuperVisor xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_dataContract xmlns:d3p1="http://schemas.datacontract.org/2004/07/Organization.Project.DataContracts" i:nil="true" />
    <d2p1:_description i:nil="true" />
    <d2p1:_hasDataContract>false</d2p1:_hasDataContract>
    <d2p1:_id xmlns:d3p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
      <d3p1:internalValue>d57db20d-9b3a-4345-849e-d5a0d0d88f70</d3p1:internalValue>
    </d2p1:_id>
  </directSalesAgentSuperVisor>
  <photos xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_list>
      <d2p1:IdentityDataReferenceOfPhotoDataContractEx>
        <d2p1:_dataContract xmlns:d5p1="http://schemas.datacontract.org/2004/07/Organization.Project.DataContracts" z:Id="i3">
          <d2p1:_isDirty>true</d2p1:_isDirty>
          <d2p1:_id xmlns:d6p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
            <d6p1:internalValue>507f45d1-ce3a-4ec2-a343-d0b83cfb7bc8</d6p1:internalValue>
          </d2p1:_id>
          <d2p1:_key>false</d2p1:_key>
          <d2p1:_keyIdentifier>SurrogateKey</d2p1:_keyIdentifier>
          <Content i:nil="true" />
          <Taken>2013-03-05T17:49:06.294006+02:00</Taken>
        </d2p1:_dataContract>
        <d2p1:_description i:nil="true" />
        <d2p1:_hasDataContract>true</d2p1:_hasDataContract>
        <d2p1:_id xmlns:d5p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
          <d5p1:internalValue>507f45d1-ce3a-4ec2-a343-d0b83cfb7bc8</d5p1:internalValue>
        </d2p1:_id>
      </d2p1:IdentityDataReferenceOfPhotoDataContractEx>
    </d2p1:_list>
  </photos>
  <salesPoint xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts">
    <d2p1:_dataContract xmlns:d3p1="http://schemas.datacontract.org/2004/07/Organization.Project.DataContracts" i:nil="true" />
    <d2p1:_description i:nil="true" />
    <d2p1:_hasDataContract>false</d2p1:_hasDataContract>
    <d2p1:_id xmlns:d3p1="http://schemas.datacontract.org/2004/07/Organization.Domain">
      <d3p1:internalValue>692a294a-2d1b-4026-9693-0c0ce552a2fb</d3p1:internalValue>
    </d2p1:_id>
  </salesPoint>
  <stockCounts xmlns:d2p1="http://schemas.datacontract.org/2004/07/Organization.DataContracts" i:nil="true" />
</VisitDataContractEx>

Tweaking the XML using Fiddler and testing submissions, I have narrowed down the problem to the element names under _list elements:

.NET:

    <d2p1:_list>
      <d2p1:IdentityDataReferenceOfCheckListAnswerDataContractExX8I0_S_SPU>

Mono:

    <d2p1:_list>
      <d2p1:IdentityDataReferenceOfCheckListAnswerDataContractEx>

This is my code which serializes the data:

public string Serialize<TDataContract>(object obj)
{
    var builder = new StringBuilder();
    var serializer = new DataContractSerializer(typeof(TDataContract));
    var xmlWriter = XmlWriter.Create(builder);
    serializer.WriteObject(xmlWriter, obj);
    xmlWriter.Close();

    return builder.ToString().Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", string.Empty);
}

Is this a bug which has to be addressed by the Mono team, or can someone suggest a possible workaround?

Edit:

I've been narrowing this problem down further and it's not about lists, it's about the way each implementation chooses XML element names.

IdentityDataReference takes a generic type, and in this case it's of type CheckListAnswerDataContractEx .

IdentityDataReference also happens to be in a distributed DLL (which I have the source code for), so my suspicion is that DataContractSerializer is using reflection to work out the name automatically, and perhaps as it's a separately distributed DLL, .NET is appending X8I0_S_SPU onto the end, however, Mono is not.

I have also discovered that I can add a name paramater to the DataContractAttribute like so: [DataContract(Name = "IdentityDataReference")] which will override the generated name to just be IdentityDataReference , it doesn't even try adding the Of Type when specified.

Unfortunately a quick test shows Mono is suffering a runtime exception when I specify the name and it tries to deserialize data.

Now that I understand the issue better, I am trying to make an isolated project which replicates the issue.

Edit - Marking as resolved:

I moved on from this project many years ago now, but decided to close this as answered by Katulus since I would feel the same today encountering the same issue. It was our hope at the time we could get "free" painless inter-platform integration with no extra work to an existing WCF service, which turned out to be naive.

Today if presented the same requirement, I would instead choose a more cross platform friendly communication protocol. If I couldn't replace the existing WCF infrastructure, then I would create some sort of facade and/or adapter (possibly in a different solution) which exposes the service over something like WebAPI using JSON serialization, talking to the original WCF service in the background.

If you are communicating between different platforms (even though .NET and Mono try to be the same), you should avoid using DataContractSerializer. There are other possible issues than just this bug. If you for example change classes on the server, all clients may stop working and vice versa. In server-client scenario where you don't have full control of both sides this can be a big issue.

I would change DataContractSerializer to XmlSerializer that you can control better on both sides. Or even implement own serialization to and from XML where you can account with future upgrades. If you add some new property on one server, you can update your deserializer in a way that it can handle if that new property is missing from some old client.

Perhaps a workaround is to use the svcutil application to generate the proxy and then use the same proxy as is. http://tutorials.csharp-online.net/WCF_Essentials%E2%80%94Generating_the_Proxy

Generally i think you should begin using the namespace of the datacontract, as it has helped me out several times identifying reference version problems it's just so very nice to have what version the code is running with proxies for. But that's another errand :)

Perhaps when making the reference, if you can add a reference to to public library holding your interface, you can use the service reference settings 'reuse types from referenced assemblies' which will then make them not make own types to the same extend.

Finally there is the, show all files visible Reference.svcmap under a service reference, this xml contains an element 'CollectionMappings', which often has been necessary to specify for my list to behave in which case this article gives some insight:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/09eefbbc-bf63-4aa3-a0cb-01a9dbd7f496/problem-sharing-custom-collection-types-between-service-and-client

That's my five cents of debugging hints,
Cheers

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM