1

我对 WCF 和相关技术非常陌生。(顺便说一下,使用 WCF 4.0。)

以下是我需要与之交互的 Web 服务的 WSDL 文件中的一些片段。

  <wsdl:binding name="MPGWCSTAOperations_v1_1SoapBinding" type="impl:MPGWCSTAOperations">
    <wsdlsoap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    ...
    <wsdl:operation name="MonitorStartLine">
      <wsdlsoap:operation soapAction="urn:v1_1.csta.ws.mpgw.gintel.com/MonitorStart" />
      <wsdl:input name="MonitorStartLineRequest">
        <wsdlsoap:body use="literal" />
      </wsdl:input>
      <wsdl:output name="MonitorStartLineResponse">
        <wsdlsoap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
    ...
  </wsdl:binding>

  <wsdl:portType name="MPGWCSTAOperations">
  ...
    <wsdl:operation name="MonitorStartLine" parameterOrder="monitorStartLine">
      <wsdl:input name="MonitorStartLineRequest" message="impl:MonitorStartLineRequest" />
      <wsdl:output name="MonitorStartLineResponse" message="impl:MonitorStartLineResponse" />
    </wsdl:operation>
    ....
  </wsdl:portType>

  <wsdl:message name="MonitorStartLineResponse" />

我的理解是,MonitorStartLine操作定义为返回响应消息MonitorStartLineResponse,定义为空消息。

我使用 Visual Studio 的项目 - 添加服务引用工具为此生成 C# 代理代码。

然后我做这样的事情:

   MPGWCSTAOperationsClient cstaOperationsClient = new MPGWCSTAOperationsClient();

   MonitorStartLine monitorStartLine = new MonitorStartLine();
   monitorStartLine.pnis = new string[] {"0000032"};

   cstaOperationsClient.MonitorStartLine(monitorStartLine);

这会导致以下异常:

System.ServiceModel.CommunicationException was unhandled
  HResult=-2146233087
  Message=Error in deserializing body of reply message for operation 'MonitorStartLine'. 
  End element 'Body' from namespace 'http://schemas.xmlsoap.org/soap/envelope/' expected. 
  Found element 'monitorStartLineResponse' from namespace 'urn:v1_1.csta.ws.mpgw.gintel.com'. Line 1, position 296.
  Source=mscorlib

使用 Fiddler 我看到的响应如下:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1
Content-Type: text/xml;charset=utf-8
Transfer-Encoding: chunked
Date: Wed, 16 Oct 2013 22:01:44 GMT

149
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <monitorStartLineResponse xmlns="urn:v1_1.csta.ws.mpgw.gintel.com"/>
  </soapenv:Body>
</soapenv:Envelope>

在我看来,它符合 WSDL。

我在想我可能会忽略这个错误(服务器永远不会更聪明),但如果可能的话,我更愿意解决这个问题。

4

2 回答 2

3

消息符合 WSDL,但在 WSDL 规范不明确的地方。.NET 不期望Body元素内没有任何内容,因为没有定义任何消息部分。发件人正在发送一个空monitorStartLineResponse元素,就像指定了单个消息部分一样,带有一个名为 的元素monitorStartLineResponse

由于 WSDL 规范存在歧义的领域,Web 服务互操作性组织成立了。开发WS-I Basic Profile 1.1规范是为了指定 WSDL 的一个子集,该子集保证可跨平台互操作。

此 WSDL 不符合 WS-I BP 1.1。


事实上,通过阅读WSDL 1.1 规范第 3.4 节,soap:operation),我看到这将被视为“文档文字绑定”,因为没有“样式”属性另有说明。

在第4.4.1 节,Bindings and Parts,R2213 中,WS-I BP 1.1 规范说:

R2213在部件属性soapbind:body值为空字符串的文档文字描述中,相应的信封必须在元素中没有元素内容soap:Body

这是 .NET 所期望的,但不是 .NET 正在接受的。

于 2013-10-17T01:52:39.190 回答
3

这是我实施的解决方法。(关于是否更好地实施解决方法或忽略异常是有争议的 - 我更喜欢这样做。)

我正在做的是在 WCF 对其调用 SOAP 处理之前修改响应消息。我只是删除了 WCF/SOAP 认为不应该存在的 XML 元素。

   /// <summary>
   /// This class is used to provide a workaround for a problem due to the (censored) server sending 
   /// responses encoded in SOAP which do not, at least according to WCF standards, conform to the 
   /// WSDL specifications published for the server. 
   /// </summary>
   public class MessageInspector : IClientMessageInspector
   {
      public object BeforeSendRequest(ref Message requestMessage, IClientChannel clientChannel)
      {
         return null;  // Method not needed
      }


      public void AfterReceiveReply(ref Message replyMessage, object correlationState)
      {
         if (replyMessage.IsFault)
            return;  // Avoid distortion of SOAP fault messages

         string messageBody;

         using (MemoryStream memoryStream = new MemoryStream())
         {
            using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream))
            {
               replyMessage.WriteMessage(xmlWriter);
               xmlWriter.Flush();
               messageBody = Encoding.UTF8.GetString(memoryStream.ToArray());
            }
         }

         messageBody = messageBody.Replace(
                     "<monitorStartLineResponse xmlns=\"urn:v1_1.csta.ws.mpgw.gintel.com\" />", "");

         using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(messageBody)))
         {
            using (XmlDictionaryReader xmlDictionaryReader = 
                XmlDictionaryReader.CreateTextReader(memoryStream, new XmlDictionaryReaderQuotas()))
            {
               Message newMessage = 
                     Message.CreateMessage(xmlDictionaryReader, int.MaxValue, replyMessage.Version);
               newMessage.Properties.CopyProperties(replyMessage.Properties);
               replyMessage = newMessage;
            }
         }
      }
   }


   /// <summary>
   /// Class needed to inject the above MessageInspector class into the WCF processing of messages.
   /// </summary>
   public class InjectInspectorBehavior : IEndpointBehavior
   {
      public void Validate(ServiceEndpoint serviceEndpoint)
      {
         // Method not needed
      }

      public void AddBindingParameters(ServiceEndpoint serviceEndpoint, 
                                       BindingParameterCollection bindingParameters)
      {
         // Method not needed
      }

      public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, 
                                        EndpointDispatcher endpointDispatcher)
      {
         // Method not needed
      }

      public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime clientRuntime)
      {
         clientRuntime.MessageInspectors.Add(new MessageInspector());
      }
   }

这通过添加此处显示的第二行来投入运行:

  _cstaOperationsClient = new MPGWCSTAOperationsClient();
  _cstaOperationsClient.Endpoint.Behaviors.Add(new InjectInspectorBehavior());

上面的代码主要基于在这两个位置找到的代码:

http://blogs.msdn.com/b/kaevans/archive/2008/01/08/modify-message-content-with-wcf.aspx

替换 WCF 消息的内容

于 2013-10-17T16:08:26.507 回答