ESTES 货件跟踪 v1.1 Web 服务,反序列化操作"货件跟踪"的回复消息正文时出错



我正在尝试开发一个简单的Windows Forms应用程序,以从最新版本的ESTES ShippingTracking v1.1 Web服务请求跟踪信息。当我执行请求时,我的程序抛出一个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:testsEstesTestsConnected ServicesESTES_TrackReference.cs:line 1394
at EstesTests.Program.TrackTest() in C:testsEstesTestsProgram.cs:line 49

-=-=-=- 编辑 -=-=-=- 我可以使用 SoapUI 成功处理请求并获得有效的响应。这让我相信我的问题特定于我的Visual Studio项目。

我的应用程序配置文件如下所示:

<?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 ShippingTracking v1.1"的原因是,我很确定我遇到的问题可能是特定于此特定Web服务的问题。如果有人已经有使用此 Web 服务的工作代码示例,则可能包括我问题的解决方案。另外,我相信其他任何尝试为ESTES开发运输客户端的人都会遇到这个问题。

-=-=-=- 结论 -=-=-=- 我的结论是,响应消息的 XML 内容不能完全符合已发布的 v1.1 WSDL 模式,并且反序列化异常特定于此 Web 服务实现版本。我在以前的v1.0版本中没有遇到过这个问题。

我今天遇到了同样的问题,并将其缩小到几个问题:

  • 事件时间戳在时区部分中缺少冒号
  • 缺少空字段 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) {
}
}
}

最新更新