我们正在尝试访问一个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代码,调用System.ServiceModel.ClientBase<T>. Channel
.CallServiceName(request)
;方法CCD_ 4只获取数据库对象并将其转换为Web服务所需的对象。
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
中的一些稍微不同的东西来防止它。
在谷歌上搜索后,我没有发现任何帮助。在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消息日志后,我在消息日志中得到了以下内容。(这是来自与上面代码不同的服务调用,但抛出了相同的异常,部分原因是此服务调用更简单,部分原因在于并非所有服务调用都被记录。我所做的唯一编辑是在不进行水平滚动的情况下使错误消息清晰可见。(
<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 Zycla所要求的,这里是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);
}
(与OP共同努力(
我刚刚看到您的服务在.asmx端点上公开,这表明这不是一个wcf服务,而是一个旧的asp.net服务。与wcf相反,Asp.net web服务的配置选项非常有限,它们不支持ws/web绑定(只有基本的http(。我的建议是切换到旧类型的代理,使用wsdl.exe工具生成它。您不需要任何配置,也不能使用wsHttpBinding,但至少您应该能够调用该服务。
我们有一个胜利者
Wiktor的评论让我研究了WCF和WSE3.0之间的互操作,并尝试通过重写Binding.CreateBindingElements
在CustomBinding
中使用MessageVersion.Soap12WSAddressingAugust2004
,从而使方法ClientName.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配置问题答案中的说明,在我的命名空间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>
我知道这已经有2年的历史了,但我想我会给出最简单的解决方案。我可能在重复上面的答案。诀窍是要意识到我们预先接受的老式asmx服务。WS-Addressing功能有两个版本(也许更多(——2005年8月和2004年8月。您可以在SOAPUI中看到这些,在测试.asmx服务时,您必须手动将WS-A版本更改为"200408"。所做的只是从本质上更改ws寻址标头:
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
至
<soap:Header xmlns:wsa="http://www.w3.org/2004/08/addressing">
所以问题是,你将如何在WCF中做到这一点?简单地说,如上所述,不使用wsHttpBinding,而是使用自定义绑定和设置消息版本。没有进一步的Adieu,相关的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>