WSE012: вход не был действительным сообщением SOAP, потому что отсутствует следующая информация: действие
Мы пытаемся получить доступ к веб-сервису (который, я считаю, также закодирован с использованием 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)
; метод 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>
Учитывая, что весь код, который выполняет реальную работу веб-сервиса, находится внутри WCF, я не совсем понимаю, в чем проблема, но, по-видимому, мне нужно что-то немного другое в моем App.config
чтобы предотвратить это.
Посмотрев в гугле, я не нашел ничего полезного. На Stackru этот оставшийся без ответа вопрос WCF с сентября 2011 года не поможет; пользовательские привязки ( ответ от ноября 2009 г. и ссылка о WSE) не помогают (и я их едва понимаю), и ответ на форуме от ноября 2009 г. и вопрос ColdFusion от октября 2009 г. не связаны. Все остальные хиты Google, которые я вижу, являются дубликатами этих ссылок.
Любая помощь будет принята с благодарностью!
Изменить, чтобы добавить больше деталей
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); }
}
}
Все остальные прокси-классы также неотредактированы из автоматически сгенерированного кода (который я редактировал здесь для оптимизации пробелов и пространств имен, чтобы он лучше подходил для экрана в Stackru; три пространства имен, которые я добавил using
операторы for были полностью определены для всех ссылок на классы, так же как и пространство имен, к которому я редактировал 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 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);
}
3 ответа
У нас есть победитель...
Комментарии Wiktor Zychla побудили меня взглянуть на Interop между WCF и WSE3.0 и попробовать использовать MessageVersion.Soap12WSAddressingAugust2004
в CustomBinding
переопределив Binding.CreateBindingElements
так что метод 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);
}
(код адаптирован из " Изменение привязки службы" в блоге Николаса Аллена в WCF).
Казалось бы , это решило мою проблему. Наконец.
Большое спасибо, Виктор и John Saunders. Я бы не добрался до этого без твоей помощи.
Изменить: еще одна неудачная попытка ниже
Опять же, ради полноты, я включу другой путь, который я пробовал, который не работал для меня. Я также попытался следовать инструкциям из этого ответа на вопрос "Конфигурация WCF CustomBinding", создав в своем пространстве имен класс Custom Binding. 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>
(совместные усилия с ОП)
Я только что видел, что ваш сервис открыт на конечной точке.asmx, что говорит о том, что это не сервис wcf, а скорее старый сервис asp.net. Веб-сервисы Asp.net в отличие от wcf имеют очень ограниченные параметры конфигурации, они не поддерживают привязку ws / web (только базовый http). Тогда мой совет - переключиться на прокси старого типа, сгенерировать его с помощью инструмента wsdl.exe. Вам не нужна никакая конфигурация, и вы не можете использовать wsHttpBinding, но по крайней мере вы должны быть в состоянии вызвать службу.
Я знаю, что это 2 года, но я решил дать самое простое решение. Возможно, я перефразирую приведенный выше ответ. Хитрость заключается в том, чтобы осознать, что услуги старой школы asmx мы предварительно принимаем. Существует 2 версии (возможно, больше) функции WS-Addressing - август 2005 года и проблемный август 2004 года. Вы можете увидеть их в SOAPUI, где вам нужно вручную изменить версию WS-A на "200408" при тестировании сервисов.asmx. Все, что делает, это по существу меняет заголовок 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, а использовать пользовательскую привязку и установить версию сообщения. Без дальнейшего 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>