I'm trying to implement a client for National Rail Enquiries' SOAP Service (http://www.livedepartureboards.co.uk/ldbws/).
I stick the WSDL (http://realtime.nationalrail.co.uk/ldbws/wsdl.aspx) into http://soapclient.com/soaptest.html, but I get back the error message "Unable to handle request without a valid action parameter. Please supply a valid soap action."; what on earth should the action be?
Thanks,
Stewart
edit:
I just used soapclient.com as a quick example. In my software, I send the following XML; I still get that I'm missing an action.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://thalesgroup.com/RTTI/2008-02-20/ldb/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:ldbt2="http://thalesgroup.com/RTTI/2008-02-20/ldb/types" xmlns:ldbt="http://thalesgroup.com/RTTI/2007-10-10/ldb/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ct="http://thalesgroup.com/RTTI/2007-10-10/ldb/commontypes" >
<SOAP-ENV:Body>
<ldbt2:GetDepartureBoardRequest xmlns:ldbt2="http://thalesgroup.com/RTTI/2008-02-20/ldb/" >
<ldbt2:numRows>5</ldbt2:numRows>
<ldbt2:crs>WAT</ldbt2:crs>
<ldbt2:filterCrs>GLD</ldbt2:filterCrs>
<ldbt2:filterType>to</ldbt2:filterType>
<ldbt2:timeOffset>0</ldbt2:timeOffset>
</ldbt2:GetDepartureBoardRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
If its a SOAP 1.1 service then you will also need to include a SOAPAction HTTP header field:
http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383528
I have come across exactly the same problem when trying to write a client for the National Rail SOAP service with Perl.
The problem was caused because the Perl module that I'm using 'SOAP::Lite' inserts a '#' in the SOAPAction header ...
SOAPAction: "http://thalesgroup.com/RTTI/2008-02-20/ldb/#GetDepartureBoard"
This is not interpreted correctly by .NET servers. I found this out from Example 3-19 in O'Reilly's Programming Web Services with SOAP . The solution was given below in section 3-20, namely you need to explicitly specify the format of the header with the 'on_action' method.
print SOAP::Lite
-> uri('urn:Example1')
-> on_action(sub{sprintf '%s/%s', #_ })
-> proxy('http://localhost:8080/helloworld/example1.asmx')
-> sayHello($name)
-> result . "\n\n";
My guess is that soapclient.com is using SOAP::Lite behind the scenes and so are hitting the same problem when talking to National Rail.
The solution is to write your own client so that you have control over the format of the SOAPAction header ... but you've probably done that already.
SOAPAction is required in SOAP 1.1 but can be empty ("").
See https://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383528
"The header field value of empty string ("") means that the intent of the SOAP message is provided by the HTTP Request-URI."
Try setting SOAPAction=""
When soapAction is missing in the SOAP 1.2 request (and many clients do not set it, even when it is specified in WSDL), some app servers (eg. jboss) infer the "actual" soapAction from {xsd:import namespace}+{wsdl:operation name}.
So, to make the inferred "actual" soapAction match the expected soapAction, you can set the expected soapAction to {xsd:import namespace}+{wsdl:operation name} in your WS definition (#WebMethod(action=...) for Java EE)
Eg. for a typical Java EE case, this helps (not the Stewart's case, National Rail WS has 'soapAction' set):
#WebMethod(action = "http://packagename.of.your.webservice.class.com/methodName")
If you cannot change the server, you will have to force client to fill soapAction.
I've just spent a while trying to get this to work an have a written a Ruby gem that accesses the API. You can read more on it's project page.
This is working code in Ruby:
require 'savon'
client = Savon::Client.new do
wsdl.document = "http://realtime.nationalrail.co.uk/LDBWS/wsdl.aspx"
end
response = client.request 'http://thalesgroup.com/RTTI/2012-01-13/ldb/GetDepartureBoard' do
namespaces = {
"xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/",
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
"xmlns:xsd" => "http://www.w3.org/2001/XMLSchema"
}
soap.xml do |xml|
xml.soap(:Envelope, namespaces) do |xml|
xml.soap(:Header) do |xml|
xml.AccessToken do |xml|
xml.TokenValue('ENTER YOUR TOKEN HERE')
end
end
xml.soap(:Body) do |xml|
xml.GetDepartureBoardRequest(xmlns: "http://thalesgroup.com/RTTI/2012-01-13/ldb/types") do |xml|
xml.numRows(10)
xml.crs("BHM")
xml.filterCrs("BHM")
xml.filterType("to")
end
end
end
end
end
p response.body
Hope that's helpful for someone!
We put together Web Services on Windows Server and were trying to connect with PHP on Apache. We got the same error. The issue ended up being different versions of the Soap client on the different servers. Matching the SOAP versions in the options on both servers solved the issue in our case.
the service have 4 operations:
1. GetServiceDetails
2. GetArrivalBoard
3. GetDepartureBoard
4. GetArrivalDepartureBoard
I have solved this problem, in Java Code, adding:
MimeHeaders headers = message.getMimeHeaders();
headers.addHeader("SOAPAction", endpointURL);
Related
I'm trying to make a call to a 3rd party webservice using Sage X3 scripts, I'm using the func ASYRWEBSER.EXEC_HTTP which is working fine and it's calling the webservice and receiving the answer
The Answer:
<s:Envelope
xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">
<s:Body>
<CreateShipmentResponse
xmlns=\"http://tempuri.org/\">
<CreateShipmentResult
xmlns:a=\"http://schemas.datacontract.org/2004/07/CTTExpressoWS\"
xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">
<a:ErrorsList/>
<a:ShipmentData>
<a:ShipmentDataOutput>
<a:ClientReference>teste</a:ClientReference>
<a:DocumentsList>
</a:DocumentsList>
<a:FirstObject>DB112320353PT</a:FirstObject>
<a:LabelList>
<a:LabelData>
<a:BestEncoding>65001</a:BestEncoding>
<a:FileName>ETI</a:FileName>
<a:Label>^XA
\n</a:Label>
</a:LabelData>
</a:LabelList>
<a:LastObject>DB112320353PT</a:LastObject>
<a:OriginalObjectID i:nil=\"true\"/>
</a:ShipmentDataOutput>
</a:ShipmentData>
<a:Status>Success</a:Status>
</CreateShipmentResult>
</CreateShipmentResponse>
</s:Body>
</s:Envelope>
My problem is that I don't know how to get the XML fields I need in X3 Scripts, can anyone point me in the right direction?
I need to get the <a:LastObject>, the <a:Status> and the <a:LabelList><a:LabelData> of the response.
Maybe I am a little late, but in case you did not solve it yet: You get the response in a clbfile variable (last parameter of EXEC_HTTP - Funprog EXEC_HTTP(HEADERCOD, HEADERVAL, DATA, RESHEAD, RESBODY)).
Here are a few options to parse the RESBODY clbfile:
Parse the content directly in 4gl.
Module in nodeJS (custom module)
Executable called by "System" instruction
I have problems to get SOAP request through Zeep, I get a (client) validation error... I have also tested with SoapUI and that does NOT give me the same validation error...
The specification below is from the server... Based on that specification, the OrderStatus and SynchStatus are needed to perform the request.
<soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/ xmlns:web="WebServiceProvider">
<soapenv:Header/>
<soapenv:Body>
<web:Order_Get>
<!--Optional:-->
<web:orderOptions>
<web:FromDate>?</web:FromDate>
<web:ToDate>?</web:ToDate>
<web:OrderStatus>?</web:OrderStatus>
<web:SynchStatus>?</web:SynchStatus>
<!--Optional:-->
<web:OrderNumber>?</web:OrderNumber>
<web:FromOrderNumberToLastRecieved>?</web:FromOrderNumberToLastRecieved>
<web:PaymentStatus>?</web:PaymentStatus>
</web:orderOptions>
</web:Order_Get>
</soapenv:Body>
</soapenv:Envelope>
However, executing this from the SoapUI without OrderStatus and SynchStatus will give me a list of all the orders for the specified dates:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="WebServiceProvider">
<soapenv:Header/>
<soapenv:Body>
<web:Order_Get>
<web:orderOptions>
<web:FromDate>2021-03-30</web:FromDate>
<web:ToDate>2021-03-31</web:ToDate>
</web:orderOptions>
</web:Order_Get>
</soapenv:Body>
</soapenv:Envelope>
I want to do the same with Zeep (https://github.com/mvantellingen/python-zeep) but the client validation fails...
I initiate the request with the following code:
api_url = 'https://abc.se/Webservice20/v3.0/webservice.asmx?WSDL'
session.auth = HTTPDigestAuth(username, password)
api = Client(api_url, transport=Transport(session=session))
And then I try to execute the following request:
order_options = {
'FromDate': '2021-03-30',
'ToDate': '2021-03-31',
}
orders = api.service.Order_Get(orderOptions=order_options)
This will result in the following error:
zeep.exceptions.ValidationError: Missing element OrderStatus (Order_Get.orderOptions.OrderStatus)
If I add OrderStatus to the request, I will get a validation error saying that SynchStatus is missing. When that has been added as well, the request is sent to the server.
I.e. it seems like the zeep client is more strict with regards to validating the data in the request than what the server is... Is there a way to force the client to skip this validation?
Many thanks in advance!
Searched a bit more and found a workaround in this post: Getting zeep.exceptions.ValidationError: Missing element for method that worked with suds
So the solution in my case looks like this:
from zeep import xsd
...
order_options = {
'FromDate': '2021-03-30',
'ToDate': '2021-03-31',
'OrderStatus': xsd.SkipValue,
'SynchStatus': xsd.SkipValue,
}
response = api.service.Order_Get(orderOptions=order_options)
This will block zeep from doing client side validation of the parameters OrderStatus and SynchStatus.
it seems like the zeep client is more strict with regards to validating the data in the request than what the server is...
Looks like it.
Looking at the request SoapUI generates based on the WSDL, the two fields you mention are mandatory:
<web:orderOptions>
<web:FromDate>?</web:FromDate>
<web:ToDate>?</web:ToDate>
<web:OrderStatus>?</web:OrderStatus>
<web:SynchStatus>?</web:SynchStatus>
<!--Optional:-->
<web:OrderNumber>?</web:OrderNumber>
<web:FromOrderNumberToLastRecieved>?</web:FromOrderNumberToLastRecieved>
<web:PaymentStatus>?</web:PaymentStatus>
</web:orderOptions>
So the error that the zeep client displays is correct. Zeep inspects the WSDL and generates the corresponding code to use the types in the contract. Your WSDL contract says that OrderStatus and SynchStatus are mandatory. The fact that the server doesn't validate them shows a problem: the web service isn't respecting it's own documented contract
The WSDL and the behavior of the web service should be the same. I suggest you contact the web service owners and ask about this behavior. It might be a validation missing on the server and what you get is just some side effect of that, or the behavior is intentional but someone forgot to update the WSDL to say that you can also make the call without those parameters.
Meanwhile, the workaround is very simple. Download the WSDL, change it to make the two fields optional, then feed this changed WSDL to zeep for it to generate the code, instead of using the original WSDL. You should however clarify this with the web service provider. If it's indeed a neglect of someone, this might be spotted at some point and fixed, making your workaround call fail a server validation because of the missing fields.
I have to tool to generate soap requests and it can do so in two ways. Either generating the request beginning with:
<soapenv:Envelope xmlns:ns="http://…" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
or with:
<soap:Envelope xmlns:ns="http://…" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
I suspect that one is the current technique and the other is the legacy technique. But since only one has something resembling a date in the url I can't figure out which is.
Which of the two it the current version to be used for new requests?
SOAP1.1 is Older.
It uses namespace as http://schemas.xmlsoap.org/soap/envelope/.
SOAP1.2 is latest.
It uses namespace as http://www.w3.org/2003/05/soap-envelope.
Refer links for more details.
Which one should be used for new services?
SOAP1.2 should be used for new services as its latest and greatest, more cleaner and robust. Though now a days trend is more for Restfull Services then SOAP.
I have created a very basic Web Service "operation" with an operation called "hello". It works perfectly from SoapUI, but when I use Matlab 2014a to call it, the input parameters are never obtained. So hello() always returns "Hello null!" and other operations, such as addition(), always returns 0. I have followed Matlab help and I am unable to see what is going on.
What I have done is:
>> createClassFromWsdl('http://ip/WebServiceTest/operation?wsdl')
ans = operation
>> obj = operation
endpoint: 'http://ip/WebServiceTest/operation'
wsdl: 'http://ip/WebServiceTest/operation?wsdl'
>> methods(obj)
addition display hello operation
>> hello(obj, 'John')
ans =
Hello null!
This demonstrates that the Web Service is called correctly and it returns an answer, but the input parameter is not obtained.
The generated code hello.m seems fine to me:
function xReturn = hello(obj,name)
%hello(obj,name)
%
% Input:
% name = (string)
%
% Output:
% return = (string)
% Build up the argument lists.
values = { ...
name, ...
};
names = { ...
'name', ...
};
types = { ...
'{http://www.w3.org/2001/XMLSchema}string', ...
};
% Create the message, make the call, and convert the response into a variable.
soapMessage = createSoapMessage( ...
'http://webservices/', ...
'hello', ...
values,names,types,'document');
response = callSoapService( ...
obj.endpoint, ...
'', ...
soapMessage);
xReturn = parseSoapResponse(response);
I have captured network traffic to see the SOAP message and Matlab sends indeed the parameter, and the message looks fine:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<hello xmlns="http://webservices/">
<name xsi:type="xs:string">John</name>
</hello>
</soap:Body>
</soap:Envelope>
The same message from SoapUI, which returns a correct Hello John! value would look like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://webservices/">
<soapenv:Header/>
<soapenv:Body>
<web:hello>
<!--Optional:-->
<name>John</name>
</web:hello>
</soapenv:Body>
</soapenv:Envelope>
What is it happening?
EDIT
I have also found this in the logs:
Received WS-I BP non-conformant Unquoted SoapAction HTTP header
After a lot of testing, I believe this is due to an error on old Matlab Web Service implementation, especially related to the lack of explicit namespace here <hello xmlns="http://webservices/">
From version 2014b there is a new way to call Web Services based on JDK and Apache CXF, and using the Web Services are called correctly. According to the documentation, the steps are:
Install and/or locate the Java JDK and Apache CXF programs.
Set the
paths to the JDK and CXF programs using the
matlab.wsdl.setWSDLToolPath function. Values for the paths are saved
across sessions in your user preferences, so you only need to
specify them once.
Change the MATLAB current folder to the location
where you want to use the files generated from the WSDL document.
You must have write-permission for this folder.
Run
matlab.wsdl.createWSDLClient, supplying the WSDL document location,
which can be a URL or a path to a file. The function converts the
server's APIs to a MATLAB class, and creates a class folder in the
current folder. The class folder contains methods for using the
server's APIs. The function always creates a constructor method that
has the same name as the class. You only need to run the
matlab.wsdl.createWSDLClient function once. You can access the class
anytime after that.
Create an object of the class whenever you want
to use the operations of the service.
View information about the
class to see what methods (operations) are available for you to use.
Use the methods of the object to run applications on and exchange
data with the server. MATLAB automatically converts XML data types
to MATLAB types, and vice versa.
Note: Depending on the version of Matlab used you might be required to provide a minimum or specific version of JDK
An example can be:
jdk = 'C:\Program Files\Java\jdk1.7.0_79'
cxf = 'C:\Program Files\apache\apache-cxf-2.7.18'
matlab.wsdl.setWSDLToolPath('JDK',jdk,'CXF',cxf)
matlab.wsdl.createWSDLClient('http://ip/WebServiceTest/operation?wsdl')
javaaddpath('.\+wsdl\operation.jar')
obj = operation
methods(obj)
hello(obj, 'John')
The newer version produces the following SOAP message:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:hello xmlns:ns2="http://webservices/">
<name>John</name>
</ns2:hello>
</S:Body>
</S:Envelope>
This question is very specific. If CUCM, AXL and SOAP doesn't tell you anything, there's no need to read further. Except you're interested.
Has anyone been successful at wsimporting the current WSDL file for Cisco AXL and supporting the AddTransPattern-Request? I'm talking about version 8.5 or "current" (as in Cisco UCM 8.6.2).
The import was successful, but adding a translation pattern doesn't work anymore.
I tested it by writing my SOAP request by hand, using soapUI in eclipse.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/8.5">
<soapenv:Header/>
<soapenv:Body>
<ns:addTransPattern sequence="?">
<transPattern>
<pattern>MYPATTERN</pattern>
<description>MYDESCRIPTION</description>
<routePartitionName>MYPARTITION</routePartitionName>
<calledPartyTransformationMask>MYDESTINATION</calledPartyTransformationMask>
<provideOutsideDialtone>false</provideOutsideDialtone>
<callingSearchSpaceName>MYCALLINGSEARCHSPACE</callingSearchSpaceName>
</transPattern>
</ns:addTransPattern>
</soapenv:Body>
The response is as follows:
<axlcode>-391</axlcode>
<axlmessage>Cannot insert a null into column (numplan.tkpatternusage).</axlmessage>
<request>addTransPattern</request>
soapUI tells me that putting usage is optional. Even if I put a value for usage, e.g. <usage>3</usage>, it tells me the value wouldn't exist even though I know it does.
Any idea is appreciated
Finally, I figured out what was wrong.
The value for <usage> needs to be a string, like in this case Translation. Then it works without any problem.