“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.
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!
“…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…”
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.
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?
[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; }
}
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=1)]
public string errorMessage{
get { return this.errorMessageField; }
set { this.errorMessageField= value; }
}
}
<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>…
…
<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>
<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>
…
Transaction_Ref.TransactionSvcClient client = new TestTxsServiceConsoleApplication.Transaction_Ref.TransactionSvcClient (“TransactionSvcSOAP11port_http”);
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));
…
crn: []
errorCode: [null]
errorMessage: [null]
[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; }
}
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=1)]
public string errorCode{
get { return this.errorCodeField; }
set { this.errorCodeField= value; }
}
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=2)]
public string errorMessage{
get { return this.errorMessageField; }
set { this.errorMessageField= value; }
}
…
crn: []
errorCode: [TXN0544]
errorMessage: [Process authentification with profile error]