Reputation: 103
My Problem:
I have a WCF Web Service that is being called by a simple .NET test client and is returning null values for several of the properties of the custom class that is being being returned.
Code:
[ServiceContract]
public interface IService
{
[OperationContract]
TotalTaxResult GetTotalTax(OrderHeader orderHeader);
}
[DataContract]
public class TotalTaxResult
{
[DataMember]
public string Message { get; set; }
[DataMember]
public ProductLineItem[] ProductLineItems { get; set; }
[DataMember]
public string ResultCode { get; set; }
[DataMember]
public DataSet ResultDataSet { get; set; }
[DataMember]
public string strTaxLinesCount { get; set; }
[DataMember]
public DataSet taxDataSet { get; set; }
[DataMember(IsRequired = true)]
public decimal TotalTax { get; set; }
[DataMember]
public Avalara.AvaTax.Adapter.TaxService.TaxLines TotalTaxLines { get; set; }
}
Soap Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:sal="http://schemas.datacontract.org/2004/07/SalesService">
<soapenv:Header/>
<soapenv:Body>
<tem:GetTotalTax>
<!--Optional:-->
<tem:orderHeader>
<!--Optional:-->
<sal:BFCustomerNumber>123456</sal:BFCustomerNumber>
<!--Optional:-->
<sal:BFStoreNumber>654321</sal:BFStoreNumber>
<!--Optional:-->
<sal:CustomerName>Nick T</sal:CustomerName>
<!--Optional:-->
<sal:Message></sal:Message>
<sal:OrderLineItems>
<!--Zero or more repetitions:-->
<sal:OrderLineItem>
<sal:ItemNumber>164080</sal:ItemNumber>
<sal:LineNumber>1</sal:LineNumber>
<sal:Price>100</sal:Price>
<sal:Quantity>1</sal:Quantity>
<sal:TaxCode>S</sal:TaxCode>
<sal:UoM>CA</sal:UoM>
</sal:OrderLineItem>
</sal:OrderLineItems>
<!--Optional:-->
<sal:PONumber>333000</sal:PONumber>
<!--Optional:-->
<sal:ResultCode></sal:ResultCode>
<!--Optional:-->
<sal:SourceSystem>WEB</sal:SourceSystem>
<sal:TestFlag>true</sal:TestFlag>
<!--Optional:-->
<sal:TotalTax></sal:TotalTax>
<!--Optional:-->
<sal:WarehouseNum>3010</sal:WarehouseNum>
<!--Optional:-->
<sal:validDest>
<!--Optional:-->
<sal:AddressCode></sal:AddressCode>
<!--Optional:-->
<sal:AddressType>S</sal:AddressType>
<!--Optional:-->
<sal:CarrierRoute>C022</sal:CarrierRoute>
<!--Optional:-->
<sal:City>SAINT LOUIS</sal:City>
<!--Optional:-->
<sal:Country>US</sal:Country>
<!--Optional:-->
<sal:County>SAINT LOUIS</sal:County>
<!--Optional:-->
<sal:FipsCode>2918900000</sal:FipsCode>
<!--Optional:-->
<sal:Latitude>30.0000</sal:Latitude>
<!--Optional:-->
<sal:Line1>1234 DELMAR DR</sal:Line1>
<!--Optional:-->
<sal:Line2></sal:Line2>
<!--Optional:-->
<sal:Line3></sal:Line3>
<!--Optional:-->
<sal:Line4>SAINT LOUIS MO 63130-6642</sal:Line4>
<!--Optional:-->
<sal:Longitude>-95.8765</sal:Longitude>
<!--Optional:-->
<sal:PostNet>631306632524</sal:PostNet>
<!--Optional:-->
<sal:PostalCode>63130-6642</sal:PostalCode>
<!--Optional:-->
<sal:Region>MO</sal:Region>
</sal:validDest>
<!--Optional:-->
<sal:validOrigin>
<!--Optional:-->
<sal:AddressCode></sal:AddressCode>
<!--Optional:-->
<sal:AddressType>H</sal:AddressType>
<!--Optional:-->
<sal:CarrierRoute>R030</sal:CarrierRoute>
<!--Optional:-->
<sal:City>SAINT CHARLES</sal:City>
<!--Optional:-->
<sal:Country>US</sal:Country>
<!--Optional:-->
<sal:County>SAINT CHARLES</sal:County>
<!--Optional:-->
<sal:FipsCode>296543210</sal:FipsCode>
<!--Optional:-->
<sal:Latitude>35.8034</sal:Latitude>
<!--Optional:-->
<sal:Line1>500 ORCHARD LAKES BLVD</sal:Line1>
<!--Optional:-->
<sal:Line2></sal:Line2>
<!--Optional:-->
<sal:Line3></sal:Line3>
<!--Optional:-->
<sal:Line4>SAINT CHARLES MO 63331-4341</sal:Line4>
<!--Optional:-->
<sal:Longitude>-95.5021</sal:Longitude>
<!--Optional:-->
<sal:PostNet>63389541997</sal:PostNet>
<!--Optional:-->
<sal:PostalCode>63331-4341</sal:PostalCode>
<!--Optional:-->
<sal:Region>MO</sal:Region>
</sal:validOrigin>
</tem:orderHeader>
</tem:GetTotalTax>
</soapenv:Body>
</soapenv:Envelope>
Soap Response:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GetTotalTaxResponse xmlns="http://tempuri.org/">
<GetTotalTaxResult xmlns:a="http://schemas.datacontract.org/2004/07/SalesService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Message>Total Tax Calc</a:Message>
<a:ProductLineItems i:nil="true"/>
<a:ResultCode>7.46</a:ResultCode>
<a:ResultDataSet i:nil="true"/>
<a:TotalTax>7.46</a:TotalTax>
<a:TotalTaxLines xmlns:b="http://schemas.datacontract.org/2004/07/Avalara.AvaTax.Adapter.TaxService"/>
<a:strTaxLinesCount>1</a:strTaxLinesCount>
<a:taxDataSet>
<xs:schema id="NewDataSet" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="TaxDataTable">
<xs:complexType>
<xs:sequence>
<xs:element name="TaxIndex" type="xs:int" minOccurs="0"/>
<xs:element name="TaxLineNo" type="xs:string" minOccurs="0"/>
<xs:element name="TaxCode" type="xs:string" minOccurs="0"/>
<xs:element name="TaxAmount" type="xs:decimal" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<NewDataSet xmlns="">
<TaxDataTable diffgr:id="TaxDataTable1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<TaxIndex>0</TaxIndex>
<TaxLineNo>1</TaxLineNo>
<TaxCode>P0000000</TaxCode>
<TaxAmount>7.46</TaxAmount>
</TaxDataTable>
</NewDataSet>
</diffgr:diffgram>
</a:taxDataSet>
</GetTotalTaxResult>
</GetTotalTaxResponse>
</s:Body>
</s:Envelope>
.NET Client Results:
'null' values for:
The only properties with their proper values are:
No exceptions are thrown during the entire process.
Ordering the interface through [DataMember(Order=1)] did not affect the results. The same properties returned as null.
If anybody has any suggestions, they'd be greatly appreciated. I'm fairly new to .NET and have been banging my head against this problem for a few days now. If any further information / code snippets are needed, please let me know. Thanks in advance.
Upvotes: 7
Views: 10203
Reputation: 131
In hopes that this will help others who really need to have a dataset serialized this is my solution.
Not only should you use the Serializable attribute you also need to implement IXmlSerializable for the custom type to serialize properly in a dataset. My datasets were coming back with blank columns on the custom types until I implemented the IXmlSerializable.
UDTs must support conversion to and from the xml data type by conforming to the contract for XML serialization. The System.Xml.Serialization namespace contains classes that are used to serialize objects into XML format documents or streams. You can choose to implement xml serialization by using the IXmlSerializable interface, which provides custom formatting for XML serialization and deserialization.
In addition to performing explicit conversions from UDT to xml, XML serialization enables you to:
Use Xquery over values of UDT instances after conversion to the xml data type.
Use UDTs in parameterized queries and Web methods with Native XML Web Services in SQL Server.
Use UDTs to receive a bulk load of XML data.
Serialize DataSets that contain tables with UDT columns.
UDTs are not serialized in FOR XML queries. To execute a FOR XML query that displays the XML serialization of UDTs, explicitly convert each UDT column to the xml data type in the SELECT statement. You can also explicitly convert the columns to varbinary, varchar, or nvarchar.
http://technet.microsoft.com/en-us/library/ms131082.aspx
Simple implementation of IXmlSerializable http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
Upvotes: 0
Reputation: 103
Thank you everyone for the input.
I fixed my problem, though I do not exactly understand why it worked.
I had the taxDataSet property of TotalTaxResult set up as a DataContract, but I did not end up using it. Simply taking out the taxDataSet property fixed my issue completely. I'm sure there is a rule of XML Serialization that I'm missing. Any explanation to prevent a repeat issue would be great.
Thanks again.
Upvotes: 0
Reputation: 43698
How did you generate your client? You might just need to regenerate or update your client. For example, if you generated the client, then added one of those properties to the server, but did not regenerate the client, then the value would get passed back tot he client, but the client would ignore it because it doesn't know what it is.
That is my best guess, anyway...
Actually, reading your question again, you stated that:
The values seem to be reaching the client program though, because the response from running a SoapUI test shows the correct values in the XML.
However comparing the list of items you say are null and the soap response:
Is null in the soap response:
<a:ProductLineItems i:nil="true"/>
Is null in the soap response:
<a:TotalTaxLines xmlns:b="http://schemas.datacontract.org/2004/07/Avalara.AvaTax.Adapter.TaxService"/>
So I have to assume that those are actually correctly returning null.
In addition, for the properties that contain these non-standard data types:
Those two data types need to me marked as [DataContract] also, or I think ISerializable will work too.
Upvotes: 4
Reputation: 1060
ProductLineItem and TaxLines fields are assumed to be marked as serialized/DataCotnracts as well. If not, you have to mark them. Regarding the data sets. Total tax can become 0 only if the data types on server (decimal) and client (something else) are different, you have to check the interface the client is working with (if this is not a proxy). The same regarding datasets, I experienced some problems in the past with DataSets only when the DataSet type is not in a list of referenced libraries, so .NET has to work with proxied type.
Upvotes: 0