Reputation: 2349
I am trying to execute SOAP calls from SoapUI, against WCF, and when the XML is being deserialized, it is trying to deserialize to private fields. Why is that happening and how can I get around it? The code is listed below:
I generated POCO classes from XSD files using the standard XSD.exe and the results look something like this:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://iec.ch/TC57/2011/MeterConfig#")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://iec.ch/TC57/2011/MeterConfig#", IsNullable = false)]
public partial class MeterConfig
{
private ComFunction[] comFunctionField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("ComFunction")]
public ComFunction[] ComFunction
{
get { return this.comFunctionField; }
set { this.comFunctionField = value; }
}
}
I have a WCF SOAP endpoint as follows:
[ServiceContract]
public class MyApi
{
[OperationContract]
public void CreateMeterConfig2(MeterConfig Payload)
{
//do nothing
}
}
I have a SoapUI test project where I provide the following XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:CreateMeterConfig2>
<tem:Payload>
</tem:Payload>
</tem:CreateMeterConfig2>
</soapenv:Body>
</soapenv:Envelope>
The error I get is:
Expecting element 'comFunctionField'
Or in full:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:DeserializationFailed</faultcode>
<faultstring xml:lang="en-ZA">The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:Payload. The InnerException message was 'Error in line 13 position 24. 'EndElement' 'Payload' from namespace 'http://tempuri.org/' is not expected. Expecting element 'comFunctionField'.'. Please see InnerException for more details.</faultstring>
</s:Fault>
</s:Body>
</s:Envelope>
Upvotes: 2
Views: 743
Reputation: 116980
Your problem is that you auto-generated a type marked with XmlSerializer
-specific attributes but are using WCF which uses DataContractSerializer
by default. When DataContractSerializer
tries to serialize a type marked with [SerializableAttribute]
but no data contract attributes, it infers a contract similar to how BinaryFormatter
works, namely that public and private fields should be serialized, not properties. (For more, see Types Supported by the Data Contract Serializer.)
To work around this problem, you can:
Configure WCF to use XmlSerializer
by applying [XmlSerializerFormatAttribute]
to your service. To do this, see How to change Wcf to use a different serializer? and Using the XmlSerializer Class, e.g.:
[ServiceContract]
[XmlSerializerFormat]
public class MyApi
{
[OperationContract]
public void CreateMeterConfig2(MeterConfig Payload)
{
//do nothing
}
}
Automatically generate your classes from your XSD with data contract attributes rather than XmlSerializer
attributes by using svcutil.exe
rather than xsd.exe
. To do this, see Generate DataContract from XSD and ServiceModel Metadata Utility Tool (Svcutil.exe).
Note that DataContractSerializer
has some limitations compared to XmlSerializer
. For instance it doesn't allow for properties to be selectively serialized as XML attributes rather than elements. For more, see XML Serialisation - When To Use DataContractSerializer / Binary / XMLSerialiser or Data Contract Serializer - How to omit the outer element of a collection. If your XSD is not compatible with these limitations you will need to use XmlSerializer
.
Upvotes: 5