ESTES ShipmentTracking v1.1 Web 服务,反序列化操作回复消息正文时出错 'shipmentTracking'
ESTES ShipmentTracking v1.1 Web Service, Error in deserializing body of reply message for operation 'shipmentTracking'
我正在尝试开发一个简单的 Windows 表单应用程序,以从最新版本的 ESTES ShipmentTracking v1.1 网络服务请求跟踪信息。当我执行请求时,我的程序抛出 System.ServiceModel.CommunicationException
我正在使用 Visual Studio 2019 和 .NET 4.6.2 C# Windows Forms 应用程序。
我使用添加服务引用过程配置了一个 Connected Service
并使用了 ESTES_Track
命名空间。
这是我的基本代码:
ESTES_Track.EstesShipmentTracking_PortTypeClient trackClient = new EstesShipmentTracking_PortTypeClient();
trackClient.ClientCredentials.UserName.UserName = "MYUSERNAME";
trackClient.ClientCredentials.UserName.Password = "MYPASSWORD";
ESTES_Track.search trackSearch = new ESTES_Track.search();
trackSearch.requestID = "TRACK" + DateTime.Now.Ticks.ToString();
trackSearch.pro = "1710394802";
ESTES_Track.shipmentTrackingRequest trackRequest = new shipmentTrackingRequest(trackSearch);
ESTES_Track.shipmentTrackingResponse trackResponse = trackClient.shipmentTracking(trackRequest);
通信异常是:
Error in deserializing body of reply message for operation 'shipmentTracking'
There is an error in XML document (1, 575)
at System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, XmlSerializer serializer, MessagePartDescription returnPart, MessagePartDescriptionCollection bodyParts, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, String action, MessageDescription messageDescription, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeReply(Message message, Object[] parameters)
at System.ServiceModel.Dispatcher.ProxyOperationRuntime.AfterReply(ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at EstesTests.ESTES_Track.EstesShipmentTracking_PortType.shipmentTracking(shipmentTrackingRequest request)
at EstesTests.ESTES_Track.EstesShipmentTracking_PortTypeClient.shipmentTracking(shipmentTrackingRequest request) in C:\tests\EstesTests\Connected Services\ESTES_Track\Reference.cs:line 1394
at EstesTests.Program.TrackTest() in C:\tests\EstesTests\Program.cs:line 49
-=-=-=-编辑-=-=-=-
我可以使用 SoapUI 成功处理请求并获得有效响应。这让我相信我的问题是我的 Visual Studio 项目特有的。
我的 App.config 文件如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Binder">
<security mode="Transport">
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://api.estes-express.com:443/ws/estesrtshipmenttracking.base.ws.provider.soapws:EstesShipmentTracking/estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Port"
binding="basicHttpBinding" bindingConfiguration="estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Binder"
contract="ESTES_Track.EstesShipmentTracking_PortType" name="estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Port" />
</client>
</system.serviceModel>
</configuration>
-=-=-=-编辑-=-=-=-
我明确将此标记为 "ESTES ShipmentTracking v1.1" 的原因是我非常确定我遇到的问题可能特定于此特定 Web 服务。如果有人已经有使用此 Web 服务的工作代码示例,那可能包括我的问题的解决方案。另外,我相信任何其他尝试为 ESTES 开发运输客户端的人都会遇到这个问题。
-=-=-=-结论-=-=-=-
我得出结论,响应消息的 XML 内容没有充分符合已发布的 v1.1 WSDL 架构,并且反序列化异常特定于此 Web 服务实现版本。我之前的v1.0版本没有遇到过这个问题
我今天遇到了同样的问题,并将其缩小为几个问题:
- eventTimeStamp 在时区部分缺少一个冒号
- 缺少空白字段xsi:nil
我写信给技术支持,但与此同时能够通过使用此处所述的自定义消息检查器操纵响应来使其正常工作https://blogs.msdn.microsoft.com/dsnotes/2015/04/14/wcf-simple-way-to-modify-serialized-response/。
您可以像这样将其添加到您的客户端:
trackClient.Endpoint.Behaviors.Add(new EstesTrackingEndpointBehavior());
希望他们能最终解决这个问题。如果出现其他问题,您可以在 AfterReceiveReply 中对响应添加其他更改:
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Xml;
namespace EstesWebService {
public class EstesTrackingMessageInspector : IClientMessageInspector {
public void AfterReceiveReply(ref Message reply, object correlationState) {
var doc = new XmlDocument();
var ms = new MemoryStream();
var writer = XmlWriter.Create(ms);
reply.WriteMessage(writer);
writer.Flush();
ms.Position = 0;
doc.Load(ms);
//fix the XML
addNil(doc.SelectNodes(".//shipments"));
foreach (XmlNode node in doc.SelectNodes(".//eventTimeStamp"))
fixDateTimeFormat(node);
ms.SetLength(0);
writer = XmlWriter.Create(ms);
doc.WriteTo(writer);
writer.Flush();
ms.Position = 0;
var reader = XmlReader.Create(ms);
reply = Message.CreateMessage(reader, int.MaxValue, reply.Version);
}
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
return null;
}
private void addNil(XmlNodeList nodes) {
foreach (XmlNode node in nodes) {
if (node.HasChildNodes)
addNil(node.ChildNodes);
else if (string.IsNullOrWhiteSpace(node.InnerText) && node.Attributes != null && node.Attributes.GetNamedItem("xsi:nil") == null) {
var attr = node.OwnerDocument.CreateAttribute("xsi", "nil", "http://www.w3.org/2001/XMLSchema-instance");
attr.Value = "true";
node.Attributes.SetNamedItem(attr);
}
}
}
private void fixDateTimeFormat(XmlNode node) {
if (node != null && !string.IsNullOrWhiteSpace(node.InnerText)) {
DateTimeOffset dt;
if (DateTimeOffset.TryParse(node.InnerText.Trim(), out dt))
node.InnerText = dt.ToString("O");
}
}
}
public class EstesTrackingEndpointBehavior : IEndpointBehavior {
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) {
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) {
clientRuntime.MessageInspectors.Add(new EstesTrackingMessageInspector());
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) {
}
public void Validate(ServiceEndpoint endpoint) {
}
}
}
我正在尝试开发一个简单的 Windows 表单应用程序,以从最新版本的 ESTES ShipmentTracking v1.1 网络服务请求跟踪信息。当我执行请求时,我的程序抛出 System.ServiceModel.CommunicationException
我正在使用 Visual Studio 2019 和 .NET 4.6.2 C# Windows Forms 应用程序。
我使用添加服务引用过程配置了一个 Connected Service
并使用了 ESTES_Track
命名空间。
这是我的基本代码:
ESTES_Track.EstesShipmentTracking_PortTypeClient trackClient = new EstesShipmentTracking_PortTypeClient();
trackClient.ClientCredentials.UserName.UserName = "MYUSERNAME";
trackClient.ClientCredentials.UserName.Password = "MYPASSWORD";
ESTES_Track.search trackSearch = new ESTES_Track.search();
trackSearch.requestID = "TRACK" + DateTime.Now.Ticks.ToString();
trackSearch.pro = "1710394802";
ESTES_Track.shipmentTrackingRequest trackRequest = new shipmentTrackingRequest(trackSearch);
ESTES_Track.shipmentTrackingResponse trackResponse = trackClient.shipmentTracking(trackRequest);
通信异常是:
Error in deserializing body of reply message for operation 'shipmentTracking'
There is an error in XML document (1, 575)
at System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, XmlSerializer serializer, MessagePartDescription returnPart, MessagePartDescriptionCollection bodyParts, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, String action, MessageDescription messageDescription, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeReply(Message message, Object[] parameters)
at System.ServiceModel.Dispatcher.ProxyOperationRuntime.AfterReply(ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at EstesTests.ESTES_Track.EstesShipmentTracking_PortType.shipmentTracking(shipmentTrackingRequest request)
at EstesTests.ESTES_Track.EstesShipmentTracking_PortTypeClient.shipmentTracking(shipmentTrackingRequest request) in C:\tests\EstesTests\Connected Services\ESTES_Track\Reference.cs:line 1394
at EstesTests.Program.TrackTest() in C:\tests\EstesTests\Program.cs:line 49
-=-=-=-编辑-=-=-=- 我可以使用 SoapUI 成功处理请求并获得有效响应。这让我相信我的问题是我的 Visual Studio 项目特有的。
我的 App.config 文件如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Binder">
<security mode="Transport">
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://api.estes-express.com:443/ws/estesrtshipmenttracking.base.ws.provider.soapws:EstesShipmentTracking/estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Port"
binding="basicHttpBinding" bindingConfiguration="estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Binder"
contract="ESTES_Track.EstesShipmentTracking_PortType" name="estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Port" />
</client>
</system.serviceModel>
</configuration>
-=-=-=-编辑-=-=-=- 我明确将此标记为 "ESTES ShipmentTracking v1.1" 的原因是我非常确定我遇到的问题可能特定于此特定 Web 服务。如果有人已经有使用此 Web 服务的工作代码示例,那可能包括我的问题的解决方案。另外,我相信任何其他尝试为 ESTES 开发运输客户端的人都会遇到这个问题。
-=-=-=-结论-=-=-=- 我得出结论,响应消息的 XML 内容没有充分符合已发布的 v1.1 WSDL 架构,并且反序列化异常特定于此 Web 服务实现版本。我之前的v1.0版本没有遇到过这个问题
我今天遇到了同样的问题,并将其缩小为几个问题:
- eventTimeStamp 在时区部分缺少一个冒号
- 缺少空白字段xsi:nil
我写信给技术支持,但与此同时能够通过使用此处所述的自定义消息检查器操纵响应来使其正常工作https://blogs.msdn.microsoft.com/dsnotes/2015/04/14/wcf-simple-way-to-modify-serialized-response/。
您可以像这样将其添加到您的客户端:
trackClient.Endpoint.Behaviors.Add(new EstesTrackingEndpointBehavior());
希望他们能最终解决这个问题。如果出现其他问题,您可以在 AfterReceiveReply 中对响应添加其他更改:
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Xml;
namespace EstesWebService {
public class EstesTrackingMessageInspector : IClientMessageInspector {
public void AfterReceiveReply(ref Message reply, object correlationState) {
var doc = new XmlDocument();
var ms = new MemoryStream();
var writer = XmlWriter.Create(ms);
reply.WriteMessage(writer);
writer.Flush();
ms.Position = 0;
doc.Load(ms);
//fix the XML
addNil(doc.SelectNodes(".//shipments"));
foreach (XmlNode node in doc.SelectNodes(".//eventTimeStamp"))
fixDateTimeFormat(node);
ms.SetLength(0);
writer = XmlWriter.Create(ms);
doc.WriteTo(writer);
writer.Flush();
ms.Position = 0;
var reader = XmlReader.Create(ms);
reply = Message.CreateMessage(reader, int.MaxValue, reply.Version);
}
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
return null;
}
private void addNil(XmlNodeList nodes) {
foreach (XmlNode node in nodes) {
if (node.HasChildNodes)
addNil(node.ChildNodes);
else if (string.IsNullOrWhiteSpace(node.InnerText) && node.Attributes != null && node.Attributes.GetNamedItem("xsi:nil") == null) {
var attr = node.OwnerDocument.CreateAttribute("xsi", "nil", "http://www.w3.org/2001/XMLSchema-instance");
attr.Value = "true";
node.Attributes.SetNamedItem(attr);
}
}
}
private void fixDateTimeFormat(XmlNode node) {
if (node != null && !string.IsNullOrWhiteSpace(node.InnerText)) {
DateTimeOffset dt;
if (DateTimeOffset.TryParse(node.InnerText.Trim(), out dt))
node.InnerText = dt.ToString("O");
}
}
}
public class EstesTrackingEndpointBehavior : IEndpointBehavior {
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) {
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) {
clientRuntime.MessageInspectors.Add(new EstesTrackingMessageInspector());
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) {
}
public void Validate(ServiceEndpoint endpoint) {
}
}
}