WCF Web服务序列化错误-返回null值
本文关键字:返回 null 错误 Web 服务 序列化 WCF | 更新日期: 2023-09-27 18:00:41
我的问题:
我有一个WCF Web服务,它由一个简单的.NET测试客户端调用,并为正在返回的自定义类的几个属性返回null值。
- 在返回对象之前,在断点处检查返回对象的值表明所有值都已正确填充,但该对象的值一收到就显示其几个属性为"null"
- 我已经阅读了其他几篇关于人们报告同一问题的stackoverflow帖子,其中几篇已经通过在界面中按字母顺序排列/分配订单来解决,但这并没有影响我的结果
- 但是,这些值似乎正在到达客户端程序,因为运行SoapUI测试的响应在XML中显示了正确的值
代码:
[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; }
}
皂液请求
<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响应:
<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客户端结果:
的"null"值
- 产品线项目
- strTaxLinesCount
- ResultDataSet作为空DataSet返回
- taxDataSet
- 纳税申报表合计为"0"
- 合计TaxLines
唯一具有正确值的属性是:
- 消息
- ResultCode
在整个过程中不会引发异常。
通过[DataMember(Order=1)]对接口进行排序不会影响结果。相同的属性返回为null。
如果有人有任何建议,我们将不胜感激。我对.NET还很陌生,几天来我一直在思考这个问题。如果需要任何进一步的信息/代码片段,请告诉我。提前谢谢。
您是如何生成客户端的?您可能只需要重新生成或更新您的客户端。例如,如果您生成了客户端,然后将其中一个属性添加到服务器,但没有重新生成客户端,则该值将传递回客户端,但客户端会忽略它,因为它不知道它是什么。
无论如何,这是我最好的猜测。。。
事实上,再次阅读你的问题,你说:
价值观似乎正在达到客户端程序,因为运行SoapUI测试的响应显示了XML中的正确值。
但是,比较您所说为空的项目列表和soap响应:
- 产品线项目
在soap响应中为null:
<a:ProductLineItems i:nil="true"/>
- 合计TaxLines
在soap响应中为null:
<a:TotalTaxLines xmlns:b="http://schemas.datacontract.org/2004/07/Avalara.AvaTax.Adapter.TaxService"/>
因此,我不得不假设这些实际上正确地返回了null。
此外,对于包含这些非标准数据类型的属性:
- ProductLineItem
- Avaara.AvaTax.Adapter.TaxService.TaxLines
这两种数据类型也需要标记为[DataContract],否则我认为ISerializable也可以。
ProductLineItem和TaxLines字段也被标记为序列化/DataCotnracts。如果没有,你必须标记它们。关于数据集。只有当服务器(十进制)和客户端(其他类型)上的数据类型不同时,总税收才能变为0,您必须检查客户端正在使用的接口(如果这不是代理)。关于数据集,我也遇到过一些问题,只有当数据集类型不在引用库列表中时,我才会使用数据集,因此.NET必须使用代理类型。
感谢大家的输入。
我解决了我的问题,尽管我不太明白为什么它有效。
我将TotalTaxResult的taxDataSet属性设置为DataContract,但我最终没有使用它。只需去掉taxDataSets属性就完全解决了我的问题。我确信我缺少一条XML序列化规则。任何防止问题再次发生的解释都是非常好的。
再次感谢。
希望这能帮助其他真正需要序列化数据集的人,这是我的解决方案。
您不仅应该使用Serializable属性,还需要为自定义类型实现IXmlSerializable,以便在数据集中正确序列化。在实现IXmlSerializable之前,我的数据集在自定义类型上都是空列。
UDT必须通过遵守xml序列化的约定来支持与xml数据类型的转换。System.Xml.Serialization命名空间包含用于将对象序列化为Xml格式文档或流的类。您可以选择使用IXmlSerializable接口来实现xml序列化,该接口为xml序列化和反序列化提供自定义格式。
除了执行从UDT到xml的显式转换外,xml序列化还使您能够:
在转换为xml数据类型后,对UDT实例的值使用Xquery。
在SQL Server中使用本机XML Web服务的参数化查询和Web方法中使用UDT。
使用UDT接收大量XML数据。
序列化包含具有UDT列的表的数据集
在FOR XML查询中未序列化UDT。要执行显示UDT的XML序列化的FOR XML查询,请在SELECT语句中将每个UDT列显式转换为XML数据类型。您还可以显式地将列转换为varbinary、varchar或nvarchar。
http://technet.microsoft.com/en-us/library/ms131082.aspx
IXmlSerializable的简单实现http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx