WCF: values disappeared in response: derived classes and serialization/deseriazlization order error
This is a second article about errors with getting data from the web-services.
WCF: Deserialization error, the response elementsdisappeared” ( http://geekswithblogs.net/LeonidGaneline/archive/2008/04/01/wcf-deserialization-error-the-response-elements-disappeared.aspx )
First time the whole elements disappeared from the response messages without any errors. Now only values of the elements disappeared.
We got a very strange error.
Our client code to one of the third-part web-service could not get the values from the response message.
Investigation given us such picture:
The response class has a base class. And the disappeared values are exactly from properties of this class. See the client proxy code that was generated by Visual Studio (Pict.1). Nothing wrong with it.
If we look at the wsdl that was the source for this proxy code (Pict.2) there is nothing wrong too.
The most strange thing is we have the right values in the response message (Pict.3). The errorCode and errorMessage elements have values but then we lost them. We can get them in the code (Pict.4). The output is on Pict.5.
How? Why?
The base class properties are the errorCode and errorMessage, the derived class property is the crn.
The question is in what order those two kind of properties serialize to the elements of the Xml message and then deserialize back to the class properties?
If service and client make serialization and deserialization in the “stack-like” order then everything is OK.
We see that service serialize the derived class properties first and the base class properties last (See Pict.3.1). What about our client? The client is waiting the message with different order of elements (see Pict.3.2)
And this is the source of the problem!

In the “Data Member Order ” article in the MSDN Library ( http://msdn.microsoft.com/en-us/library/ms729813.aspx ) we see:

“…The basic rules for data ordering include:
If a data contract type is a part of an inheritance hierarchy, data members of its base types are always first in the order…”

And there is no way to change this behaviour.
That’s exactly how my client proxy is working. It is waiting the base class properties on the first place and have not get them, and because these properties have minOccurs=”0″ and nillable=”true” attributes the proxy just decided that Xml message does not have properties at all and silently goes on to the first derived class property.
Unfortunately the third-part service uses the opposite order (it uses a java Axis2 service), data members of its base types are always last in the order in the serialized Xml messages.
BTW Here (http://www.onjava.com/pub/a/onjava/excerpt/JavaRMI_10/index.html?page=4) is mentioned that Java uses the same algorithm as WCF. Why doesthis consuming service use the opposite order? I have no idea.
Jeff W. Barnes in (http://jeffbarnes.net/portal/blogs/jeff_barnes/archive/2007/05/08/wcf-serialization-order-in-data-contracts.aspx) mentioned thet there isthe solution but does not give it.

Is it possible to change the proxy code on my side to follow the service order? I don’t know such options. Seems the WCF-classes where the whole deserialization occurs cannot be tuned up to change this order. Look one more time to the wsdl code (Pict.2). There is nothing about this order, ther is only the complexType the AddNewCreditCardResponse with the extension base=”ax21:ResponseData”.
Seems the only way to fix the problem is to change the auto generated code for the response message classes and force the right order. (Pict.6) OK from the point of view of WCF it is a wrong code, but what else we could do in this situation?

After these changes we’ve got the right result (see Pict.7).
=======================================================================
[Pict.1: autogenerated proxy code]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace=”http://data.transaction.com/xsd”)]
public partial class AddNewCreditCardResponse : ResponseData {

private string crnField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=0)]
public string crn {
get { return this.crnField; }
set { this.crnField = value; }
}
}

[System.Xml.Serialization.XmlIncludeAttribute(typeof(AddNewCreditCardResponse))]
[System.Xml.Serialization.XmlTypeAttribute(Namespace=”http://data.transaction.com/xsd”)]
public partial class ResponseData {

private string errorCodeField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=0)]
public string errorCode{
get { return this.errorCodeField; }
set { this.errorCodeField= value; }
}

private string errorMessageField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=1)]
public string errorMessage{
get { return this.errorMessageField; }
set { this.errorMessageField= value; }
}
}
[Pict.2: wsdl code]
<xs:complexType name=”AddNewCreditCardResponse”>
<xs:complexContent mixed=”false”>
<xs:extension base=”ax21:ResponseData”>
<xs:sequence>
<xs:element minOccurs=”0″ name=”crn” nillable=”true” type=”xs:string” />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>

<xs:complexType name=”ResponseData”>
<xs:sequence>
<xs:element minOccurs=”0″ name=”errorCode” nillable=”true” type=”xs:string” />
<xs:element minOccurs=”0″ name=”errorMessage” nillable=”true” type=”xs:string” />
</xs:sequence>
</xs:complexType>…
[Pict.3.1: original response message]

<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/”>
<soapenv:Body>
<ns:addNewCreditCardResponse xmlns:ns=”http://service.transaction.com”>
<ns:return type=”com.transaction.data.AddNewCreditCardResponseData” xmlns:ax21=”http://data.transaction.com/xsd”>
<ax21:crn/>
<ax21:errorCode>TXN056</ax21:errorCode>
<ax21:errorMessage>Process auth with create profile error</ax21:errorMessage>
</ns:return>
</ns:addNewCreditCardResponse>
</soapenv:Body>
</soapenv:Envelope>
[Pict.3.2: response sample with “WCF” order]
<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/”>
<soapenv:Body>
<ns:addNewCreditCardResponse xmlns:ns=”http://service.transaction.com”>
<ns:return type=”com.transaction.data.AddNewCreditCardResponse” xmlns:ax21=”http://data.transaction.com/xsd”>
<ax21:errorCode>TXN0544</ax21:errorCode>
<ax21:errorMessage>Process authentification with profile error</ax21:errorMessage>
<ax21:crn/>
</ns:return>
</ns:addNewCreditCardResponse>
</soapenv:Body>
</soapenv:Envelope>
[Pict.4: test code]

Transaction_Ref.TransactionSvcClient client = new TestTxsServiceConsoleApplication.Transaction_Ref.TransactionSvcClient (“TransactionSvcSOAP11port_http”);
Transaction_Ref.addNewCreditCardResponse addNewCreditCardResponse = client.addNewCreditCard(…);
Console.WriteLine(“crn: [{0}]”, (addNewCreditCardResponse.crn == null ? “null” : addNewCreditCardResponse.crn));
Console.WriteLine(“errorCode: [{0}]”, (addNewCreditCardResponse.errorCode == null ? “null” : addNewCreditCardResponse.errorCode));
Console.WriteLine(“errorMessage: [{0}]”, (addNewCreditCardResponse.errorMessage == null ? “null” : addNewCreditCardResponse.errorMessage));
[Pict.5: output with original proxy code]
crn: []
errorCode: [null]
errorMessage: [null]
[Pict.6: changed proxy code]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace=”http://data.transaction.com/xsd”)]
public partial class AddNewCreditCardResponse {

private string crnField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=0)]
public string crn {
get { return this.crnField; }
set { this.crnField = value; }
}

private string errorCodeField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=1)]
public string errorCode{
get { return this.errorCodeField; }
set { this.errorCodeField= value; }
}
private string errorMessageField;
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=2)]
public string errorMessage{
get { return this.errorMessageField; }
set { this.errorMessageField= value; }
}
[Pict.7: output with changed proxy code]
crn: []
errorCode: [TXN0544]
errorMessage: [Process authentification with profile error]
=========================================
Please, give me a feedback!