WCF Web Service serialization error - returning null values

My problem:

I have a WCF web service that is called by a simple .NET test client and returns null for several properties of the returned user class.

  • Checking the values ​​of the returned object at the breakpoint before returning it shows that all the values ​​are correctly filled, but the value of this object, as soon as it is received, shows that some of its properties are null.
  • I read several other stackoverflow posts for people reporting the same problem, and several of them were resolved by alphabet / order assignment in [DataContracts] in the interface, but this did not affect my results.
  • The values ​​seem to reach the client program because the response from running the SoapUI test shows the correct values ​​in XML.

The 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:

  • ProductLineItems
  • strTaxLinesCount
  • ResultDataSet returns as an empty DataSet
  • taxDataSet
  • TotalTax returns as '0'
  • TotalTaxLines

The only properties with their own values ​​are:

  • Message
  • ResultCode

An exception is not excluded throughout the process.

Ordering an interface through [DataMember (Order = 1)] did not affect the results. The same properties as null.

If anyone has any suggestions, they will be very grateful. I am new to .NET and have been banging my head on this issue for several days now. If you need more information / code snippets, please let me know. Thanks in advance.

+6
source share
4 answers

How did you create your client? You just need to restore or upgrade your client. For example, if you created a client, then you added one of these properties to the server, but did not regenerate the client, then the value will be transferred back to the client, but the client will ignore it because it does not know what it is.

This is my best guess, anyway ...


Actually, after reading your question again, you stated that:

The values ​​seem to reach the client program, though, since the response from running the SoapUI test shows the correct values ​​in XML.

However, comparing the list of items you say is a null and soapy answer:

  • ProductLineItems

There is a null value in the response to the soap:

 <a:ProductLineItems i:nil="true"/> 
  • TotalTaxLines

There is a null value in the response to soap:

 <a:TotalTaxLines xmlns:b="http://schemas.datacontract.org/2004/07/Avalara.AvaTax.Adapter.TaxService"/> 

Therefore, I must assume that they really return null correctly.


In addition, for properties containing these non-standard data types:

  • ProductLineItem
  • Avalara.AvaTax.Adapter.TaxService.TaxLines

These two types of data should also be marked as [DataContract] for me, or I think ISerializable will work too.

+3
source

It is assumed that the ProductLineItem and TaxLines fields will be marked as serialized / DataCotnracts. If not, you should mark them. Regarding datasets. The general tax can become 0 only if the data types on the server (decimal) and the client (something else) are different, you need to check the interface the client works with (if it is not a proxy server). The same applies to datasets, in the past I experienced some problems with a DataSet only when the DataSet type is not in the list of libraries that are referenced, so .NET should work with a proxy type.

0
source

Thank you all for your input.

I fixed my problem, although I do not quite understand why this worked.

I had a taxDataSet TotalTaxResult property configured as a DataContract, but I did not use it. Just pulling out the taxDataSet property, I completely fixed my problem. I am sure there is an XML serialization rule that I am missing. Any explanation to prevent a recurrence of the problem would be great.

Thanks again.

0
source

In the hope that this will help others who really need to serialize the dataset, this is my solution.

Not only should you use the Serializable attribute, you also need to implement IXmlSerializable for a custom type for proper serialization in the dataset. My datasets returned with empty columns in user types until I implemented IXmlSerializable.

UDTs must support conversion to and from the xml data type, in accordance with the contract for serializing XML. The System.Xml.Serialization namespace contains classes that are used to serialize objects in documents or XML-formatted streams. You can implement xml serialization 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 allows you to:

Use Xquery over the values ​​of UDT instances after conversion to xml data type.

Use UDT in parameterized queries and web methods using native XML web services on SQL Server.

Use UDT to get bulk XML data loading.

Serialize DataSets containing tables with UDT columns.

UDTs are not serialized in FOR XML queries. To execute a FOR XML query that displays UDT XML serialization, explicitly convert each UDT column to the xml data type in the SELECT statement. You can also explicitly convert 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

0
source

Source: https://habr.com/ru/post/891481/


All Articles