2

我们正在尝试访问一个 web 服务(我相信它也是使用 WCF 编码的,但我无法控制它)并且我得到一个异常:

System.ServiceModel.FaultException:WSE012:输入不是有效的 SOAP 消息,因为缺少以下信息:操作。
服务器堆栈跟踪:

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)

在 [0] 处重新抛出异常:

at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(
   IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(
   MessageData& msgData, Int32 type)
at ClientName.ProjectName.Services.ServiceName.ServiceNameSoap.CallServiceName(
   Request request)
at ClientName.ProjectName.Scheduler.ThirdPartyName.ProcessServiceName.Execute(
   Object state) in ...\ProcessServiceName.cs:line 65

调用代码ProcessServiceName.Execute如下:

Request serviceRequest = request.BuildServiceRequest();
Result result = client.CallServiceName(serviceRequest);
LogServiceErrors(db, request.ServiceNameRequestId, result.errors);

异常来自第二行,它直接调用服务引用自动生成的 WCF 代码,调用; 该方法只获取数据库对象并将其转换为 Web 服务所需的对象。System.ServiceModel.ClientBase<T>. Channel.CallServiceName(request)BuildServiceRequest

App.config(这在 Windows 服务中调用)的相关部分内容如下:

<system.serviceModel>
   <bindings>
      <webHttpBinding>
         <binding name="webBinding">
         </binding>
      </webHttpBinding>
      <wsHttpBinding>
         <binding name="ThirdPartySoap" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00"
          sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false"
          hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288"
          maxReceivedMessageSize="65536" messageEncoding="Text"
          textEncoding="utf-8" useDefaultWebProxy="true">
            <readerQuotas maxDepth="32" maxStringContentLength="8192"
             maxArrayLength="16384" maxBytesPerRead="4096"
             maxNameTableCharCount="16384"/>
            <security mode="Transport">
               <transport clientCredentialType="Basic" proxyCredentialType="None"
                realm="www.serviceprovider.com"/>
               <message clientCredentialType="UserName"
                algorithmSuite="Default"/>
            </security>
         </binding>
      </wsHttpBinding>
   </bindings>
   <client>
      <endpoint name="ServiceNameSoap"
       address="https://www.serviceprovider.com/ServiceName.asmx"
       binding="wsHttpBinding" bindingConfiguration="ThirdPartySoap"
       contract="ServiceName.ServiceNameSoap"/>
   </client>
</system.serviceModel>

鉴于执行实际 web 服务工作的所有代码都来自 WCF,我不太明白问题出在哪里,但大概我需要一些稍微不同的东西App.config来防止它。

看过Google后,我没有找到任何帮助。在 StackOverflow 上,2011 年 9 月的这个未回答的 WCF 问题没有任何帮助;自定义绑定(2009 年 11 月的回答关于 WSE 的链接)没有帮助(我几乎不理解它们),2009 年 11 月的论坛回答和 2009 年10月的 ColdFusion 事情都无关。我看到的所有其他谷歌点击都是这些链接的副本。

任何帮助将不胜感激!


编辑以添加更多细节

Wiktor Zychla正确地指出问题可能(理论上)出在代理类中。但是,这些类是完全未经自动生成的类编辑的;例如:

using System.CodeDom.Compiler;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace ClientName.ProjectName.Services.ServiceName
{
   [GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
   public interface ServiceNameSoapChannel : ServiceNameSoap, IClientChannel {}

   [System.Diagnostics.DebuggerStepThroughAttribute()]
   [GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
   public partial class ServiceNameSoapClient : ClientBase<ServiceNameSoap>,
     ServiceNameSoap
   {
     public ServiceNameSoapClient() { }

     public ServiceNameSoapClient(string endpointConfigurationName) : 
       base(endpointConfigurationName) { }

     public ServiceNameSoapClient(string endpointConfigurationName,
       string remoteAddress) :
       base(endpointConfigurationName, remoteAddress) { }

     public ServiceNameSoapClient(string endpointConfigurationName,
       EndpointAddress remoteAddress) :
       base(endpointConfigurationName, remoteAddress) { }

     public ServiceNameSoapClient(Binding binding,
       EndpointAddress remoteAddress) : base(binding, remoteAddress) { }

     public Result CallServiceName(Request request)
     { return base.Channel.CallServiceName(request); }
   }
}

所有其他代理类同样未从自动生成的代码中编辑(我在此处为空白和命名空间优化进行了编辑,以便它更适合 StackOverflow 中的屏幕;我为其添加using语句的三个命名空间在所有方面都是完全合格的类引用,就像我ClientName.ProjectName.Services.ServiceName在这些示例中编辑的命名空间一样。

添加WCF Message Logging后,我在消息日志中得到以下信息。(这是来自与上面代码不同的服务调用,但抛出相同的异常,部分原因是此服务调用更简单,部分原因是由于某种原因并非所有服务调用都被记录。我所做的唯一编辑是错误信息清晰易读,无需水平滚动。)

<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
  <System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
    <EventID>0</EventID>
    <Type>3</Type>
    <SubType Name="Information">0</SubType>
    <Level>8</Level>
    <TimeCreated SystemTime="2013-01-18T12:00:04.7166250Z" />
    <Source Name="System.ServiceModel.MessageLogging" />
    <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
    <Execution ProcessName="ClientName.ProjectName.Scheduler" ProcessID="8600" ThreadID="10" />
    <Channel/>
    <Computer>MachineNameRedacted</Computer>
  </System>
  <ApplicationData>
    <TraceData>
      <DataItem>
        <MessageLogTraceRecord Time="2013-01-18T12:00:04.7166250+00:00" Source="TransportSend" Type="System.ServiceModel.Dispatcher.OperationFormatter+OperationFormatterMessage" xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
          <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
            <s:Header>
              <a:Action s:mustUnderstand="1">http://www.serviceprovider.com/RedactedActionName</a:Action>
              <a:MessageID>urn:uuid:395d6394-5f4b-4954-8df0-8fb82d17072a</a:MessageID>
              <a:ReplyTo>
                <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
              </a:ReplyTo>
              <a:To s:mustUnderstand="1">https://www.serviceprovider.com/ServiceName.asmx</a:To>
            </s:Header>
            <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
              <RedactedActionName xmlns="http://www.serviceprovider.com">
                <brandId>2</brandId>
              </RedactedActionName>
            </s:Body>
          </s:Envelope>
        </MessageLogTraceRecord>
      </DataItem>
    </TraceData>
  </ApplicationData>
</E2ETraceEvent>
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
  <System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
    <EventID>0</EventID>
    <Type>3</Type>
    <SubType Name="Information">0</SubType>
    <Level>8</Level>
    <TimeCreated SystemTime="2013-01-18T12:00:04.7635000Z" />
    <Source Name="System.ServiceModel.MessageLogging" />
    <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
    <Execution ProcessName="ClientName.ProjectName.Scheduler" ProcessID="8600" ThreadID="10" />
    <Channel/>
    <Computer>MachineNameRedacted</Computer>
  </System>
  <ApplicationData>
    <TraceData>
      <DataItem>
        <MessageLogTraceRecord Time="2013-01-18T12:00:04.7635000+00:00" Source="TransportReceive" Type="System.ServiceModel.Channels.BufferedMessage" xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
          <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
            <env:Header xmlns:env="http://www.w3.org/2003/05/soap-envelope">
              <wsa:Action>http://schemas.xmlsoap.org/ws/2004/08/addressing/fault</wsa:Action>
              <wsa:MessageID>urn:uuid:b72c6f30-8409-4b55-8c79-056d82f990a5</wsa:MessageID>
              <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
            </env:Header>
            <soap:Body>
              <soap:Fault>
                <soap:Code>
                  <soap:Value>soap:Sender</soap:Value>
                </soap:Code>
                <soap:Reason>
                  <soap:Text xml:lang="en">
                    WSE012: The input was not a valid SOAP message because
                    the following information is missing: action.
                  </soap:Text>
                </soap:Reason>
              </soap:Fault>
            </soap:Body>
          </soap:Envelope>
        </MessageLogTraceRecord>
      </DataItem>
    </TraceData>
  </ApplicationData>

更多细节:ServiceNameSoap 接口

正如Wiktor Zychla所要求的,这里是ServiceNameSoap接口声明,来自自动生成的代码,再次编辑只是为了更好地适应屏幕(因此是using)并编辑客户机密名称:

using System.ServiceModel;

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel","4.0.0.0")]
[ServiceContractAttribute(Namespace="https://www.serviceprovider.com/",
    ConfigurationName="ServiceName.ServiceNameSoap")]
public interface ServiceNameSoap
{
    [OperationContractAttribute(
        Action="https://www.serviceprovider.com/ServiceName",
        ReplyAction="*")]
    [XmlSerializerFormatAttribute(SupportFaults=true)]
    [ServiceKnownTypeAttribute(typeof(ClientRequest))]
    [return: MessageParameterAttribute(Name="result")]
    ClientName.ProjectName.Services.ServiceName.Result CallServiceName(
        ClientName.ProjectName.Services.ServiceName.Request request);
}
4

3 回答 3

1

(与 OP 共同努力)

我刚刚看到您的服务暴露在 .asmx 端点上,这表明这不是 wcf 服务,而是旧的 asp.net 服务。与 wcf 相比,Asp.net Web 服务的配置选项非常有限,它们不支持 ws/web 绑定(仅支持基本的 http)。然后我的建议是切换到旧类型代理,使用 wsdl.exe 工具生成它。您不需要任何配置,也不能使用 wsHttpBinding,但至少您应该能够调用该服务。

于 2013-01-21T10:50:15.297 回答
1

我们有一个赢家……</h2>

Wiktor的评论使我查看了WCF 和 WSE3.0 之间的 Interop,并尝试通过覆盖使用MessageVersion.Soap12WSAddressingAugust2004in a ,以便方法从:CustomBindingBinding.CreateBindingElementsClientName.ProjectName.Services. ServiceName.ServiceNameSoapClient.CallServiceName

public Result CallServiceName(Request request)
{
    return base.Channel.CallServiceName(request);
}

(如在原始问题中)到:

using System.ServiceModel.Channels;

public Result CallTestDrive(Request request)
{
    BindingElementCollection elements
        = base.Endpoint.Binding.CreateBindingElements();
    elements.Find<MessageEncodingBindingElement>().MessageVersion
        = MessageVersion.Soap12WSAddressingAugust2004;
    base.Endpoint.Binding = new CustomBinding(elements);

    return base.Channel.CallTestDrive(request);
}

(代码改编自Nicholas Allen 的 WCF 博客的修改服务绑定)。

似乎解决了我的问题。最后。

非常感谢 Wiktor 和John Saunders;如果没有你的帮助,我不会做到这一点。


编辑:下面的另一个失败尝试

再次为了完整起见,我将包括我尝试过的另一种对我不起作用的途径。我还尝试按照这个问题 WCF CustomBinding Configuration 的答案中的说明,在我的命名空间中创建一个自定义绑定类ClientName.ProjectName.ServiceName

using System.ServiceModel;
using System.ServiceModel.Channels;

public class CustomWsHttpBinding : WSHttpBinding
{
    public override BindingElementCollection CreateBindingElements()
    {
        BindingElementCollection elements = base.CreateBindingElements();

        MessageEncodingBindingElement encodingElement
          = elements.Find<MessageEncodingBindingElement>();
        encodingElement.MessageVersion
          = MessageVersion.Soap12WSAddressingAugust2004;

        return elements;
    }
}

并将其添加到配置中:

<system.serviceModel>
    <extensions>
        <bindingExtensions>
            <add name="CustomWsHttpBinding"
             type="ClientName.ProjectName.ServiceName.CustomWsHttpBinding, ClientName.ProjectName.ServiceName" />
        </bindingExtensions>
    </extensions>
    <bindings>
        <CustomWsHttpBinding>
            <binding name="ServiceNameSoap" closeTimeout="00:01:00"
             openTimeout="00:01:00" receiveTimeout="00:10:00"
             sendTimeout="00:01:00" allowCookies="false"
             bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
             maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
             messageEncoding="Text" textEncoding="utf-8"
             useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192"
                 maxArrayLength="16384" maxBytesPerRead="4096"
                 maxNameTableCharCount="16384"/>
                <security mode="Transport">
                    <transport clientCredentialType="Basic"
                     proxyCredentialType="None" realm="www.serviceprovider.com"/>
                    <message clientCredentialType="UserName"
                     algorithmSuite="Default"/>
                </security>
            </binding>
        </CustomWsHttpBinding>
    </bindings>
    <!-- ... -->
</system.serviceModel>
于 2013-01-21T15:18:41.747 回答
1

我知道这是 2 岁,但我想我会给出最简单的解决方案。我可能会重复上述答案。诀窍是要认识到我们预先接受 ws-* 的老式 asmx 服务。WS-Addressing 功能有 2 个版本(可能更多) - 2005 年 8 月和有问题的 2004 年 8 月。您可以在 SOAPUI 中看到这些版本,您必须在测试 .asmx 服务时手动将 WS-A 版本更改为“200408”。所做的只是将 ws-addressing 标头从以下位置更改:

<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">

<soap:Header xmlns:wsa="http://www.w3.org/2004/08/addressing">

所以问题是,你将如何在 WCF 中做到这一点?简单地说,如上所述,不使用 wsHttpBinding 而是使用自定义绑定和设置消息版本。没有进一步的再见,相关的 WebConfig:

<system.serviceModel> <client> <endpoint address="http://localhost/some_old_school_garbage_service/adapterws.asmx" binding="customBinding" bindingConfiguration="AdapterWSSoap" contract="AdapterWS.AdapterWSSoap" name="LodestarASMX" /> </client> <bindings> <customBinding> <binding name="AdapterWSSoap" > <security authenticationMode="UserNameOverTransport" allowInsecureTransport="True"></security> <textMessageEncoding messageVersion="Soap12WSAddressingAugust2004"></textMessageEncoding> <httpTransport/> </binding> </customBinding>

于 2015-12-28T20:49:59.540 回答