How to deserialize soap response with multiref in .net? - xml-deserialization

I am making a .net wcf client for java ws. But when I make a request, and response contains fault, it also contains multiRef section. So I get this exception:
Server returned an invalid SOAP Fault.
End element 'Body' from namespace 'http://schemas.xmlsoap.org/soap/envelope expected. Found element 'multiRef' from namespace ''
This is how response from server looks like (taken directly from network):
<soapenv:Envelope>
<soapenv:Header/>
<soapenv:Body>
<soapenv:Fault>...</soapenv:Fault>
<multiRef>...</multiRef>
</soapenv:Body>
</soapenv:Envelope>
Is there any way to configure my wcf client to deserialize that message right ? Or a possibility to get a raw response xml?

Related

SOAP request with certain tags without namespace

Would be the following SOAP request valid according to the standard?
<?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>
<ns2:ServiceReq xmlns:ns2="http://www.tibco.com/service" xmlns:ns1="http://www.tibco.com/framework">
<ns1:HeaderIn>
<ns1:countryISO>FR</ns1:countryISO>
<ns1:callerDateTime>2021-11-26T15:50:08.742Z</ns1:callerDateTime>
</ns1:HeaderIn>
<ns2:request>
<entete>
<profile>Default</profile>
</entete>
<input>
<type>W</type>
<codeRegion>X</codeRegion>
</input>
</ns2:request>
</ns2:ServiceReq>
</soapenv:Body>
</soapenv:Envelope>
I am not sure because certain tags don't have a namespace
There are multiple levels of valid here:
Is it a valid SOAP message as per the SOAP standard? Yes. The SOAP envelope and body tags seem valid.
Is it a valid XML format? Yes, it's a well formed XML file.
Are those elements without a namespace prefix valid? Yes. Elements can be in a default namespace or in no namespace at all.
Is the actual content of the body a valid messages? You can only tell if you verify the message you posted against the expected message as defined in the WSDL file of the web service.
All the elements in the body of the SOAP message should belong to specific namespaces, but sometimes a developer forgets to add a namespace annotation on the element, or copy-pastes something from some place else, or whatever, and you end up with weird looking XMLs like that. The service works and the message is correctly parsed, but it just looks funny.

Problem with validation of SOAP request with Zeep (python)

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.

What are Servicenow SOAP API getkeys wildcards?

I'd like to use a SOAP request to get a list of items in servicenow table, that have description starting with "TEST".
I am able to send a simple getKeys request. For example the below one is successfully returning to me the sys_id of a single ticket:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:hr="http://www.service-now.com/hr_case">
<soapenv:Header/>
<soapenv:Body>
<hr:getKeys>
<short_description>TEST Soap 1</short_description>
</hr:getKeys>
</soapenv:Body>
</soapenv:Envelope>
How should I modify the above request, so that it returns keys of all items with description starting with "TEST"?
I've used instead a REST webservice with the URI:
https://???.service-now.com/api/now/table/hr_case?sysparm_query=short_descriptionSTARTSWITHTEST
before then I tried a URI like that:
https://???.service-now.com/api/now/table/hr_case?&short_description=TEST Soap 1

How to access body of payload for a camel-cxf endpoint

I have my CXF based Jax-WS webservice and trying to read Payload of request.
I have org.apache.camel.component.cxf.CxfEndpoint whose Dataformat I am setting to Payload.
I am making call to this Service with POST method with body as Soap envelope as follows.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:loc="http://www.csapi.org/schema/parlayx/terminal_location/v2_0/local">
<soapenv:Header/>
<soapenv:Body>
<loc:getLocation>
<loc:address>tel:+948420161525</loc:address>
<loc:requestedAccuracy>500</loc:requestedAccuracy>
<loc:acceptableAccuracy>500</loc:acceptableAccuracy>
</loc:getLocation>
</soapenv:Body>
</soapenv:Envelope>
Here body is representation of GetLocation object of ParlayX protocol.
In my class, I receive CxfPayload object. I want to retrieve address and requestedAccuracy from the Payload body.
I tried to extract required data from getBodySources() and getBody() methods of CxfPayload. But could not succeed. I don't see the required data in the object.
I referred some examples from link but could not succeed too.
Any idea how I can extract body data of payload ?
There are a few ways you can do this. For example you can unmarshal it into a POJO and access it using Java methods. Or if you just want a few values from the payload, you can simply use XPath:
<setHeader headerName="address">
<xpath>//loc:address/text()</xpath>
</setHeader>
Which sets the address in the address header.
Edit:
To use xpath on your payload in Java, something like this should do the trick:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(BODY_IN_STRING)));
XPath xPath = XPathFactory.newInstance().newXPath();
String address = xPath.evaluate("//loc:address/text()", document));

SoapUI Pro, validating response using groovy script

I am using SoapUI Pro to test web services used for creating postal despatch shipments.
I am using a groovy script to validate my web service requests. If I am expecting the request to succeed I look for a value of ‘Allocated’ in the ‘status’ field. If I am expecting the request to fail I look for the correct error code and errorDescription in the integration footer.
Sometimes a valid request will have a warning message (e.g. to inform user that field data is too long and has been truncated). I also want to validate these warning messages as well.
I specify the element path that I want to validate in my data source file and then pass it to my groovy script that does the validation.
The groovy script retrieves the value in the element path and assigns it to a variable actualReturn1 using ..
actualReturn1 = holder.getNodeValue(testElementOne);
where testElementOne could be either
//NS1:completedShipmentInfo/NS1:status/status/statusCode/code
OR
//NS1:createShipmentResponse/NS1:integrationFooter/errors/error/errorCode
The first path is valid and correctly assigns the value of this status field to actualReturn1.
But the second path does not appear to be valid and assigns null to actualReturn1.
Below are part of my 2 response files the elements I’m trying to extract data from.
Response with status element that is extracted successfully..
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<NS1:createShipmentResponse xmlns:NS1="http://www.royalmailgroup.com/api/ship/V1">
<NS1:integrationHeader>
<dateTime xmlns="http://www.royalmailgroup.com/integration/core/V1">2013-12-02T17:06:11</dateTime>
<version xmlns="http://www.royalmailgroup.com/integration/core/V1">1</version>
<identification xmlns="http://www.royalmailgroup.com/integration/core/V1">
<applicationId>111111113</applicationId>
<transactionId>420642961</transactionId>
</identification>
</NS1:integrationHeader>
<NS1:completedShipmentInfo>
<NS1:status>
<status>
<statusCode>
<code>Allocated</code>
</statusCode>
</status>
Response with errorCode that can not be extracted…
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<NS1:createShipmentResponse xmlns:NS1="http://www.royalmailgroup.com/api/ship/V1">
<NS1:integrationHeader>
<dateTime xmlns="http://www.royalmailgroup.com/integration/core/V1">2013-12-02T17:06:13</dateTime>
<version xmlns="http://www.royalmailgroup.com/integration/core/V1">1</version>
<identification xmlns="http://www.royalmailgroup.com/integration/core/V1">
<applicationId>111111113</applicationId>
<transactionId>420642961</transactionId>
</identification>
</NS1:integrationHeader>
<NS1:integrationFooter>
<errors xmlns="http://www.royalmailgroup.com/integration/core/V1">
<error>
<errorCode>E1101</errorCode>
<errorDescription>Name is a required field</errorDescription>
</error>
</errors>
Could someone tell me why this isn't working for the second response? If I have warning messages in a valid response then I'm also not able to extract the value. Is it because this is in the integrationFooter?
Happened to see this now, so adding the answer.
In the 2nd case, it was not working for you because of the namespace issue.
The element, errors is using default namespace and is different from its parent element integrationFooter. And in your xpath, no namespace was referred to element errors and its child elements.
Here is the script that works for 2nd case:
def xml = '''
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<NS1:createShipmentResponse xmlns:NS1="http://www.royalmailgroup.com/api/ship/V1">
<NS1:integrationHeader>
<dateTime xmlns="http://www.royalmailgroup.com/integration/core/V1">2013-12-02T17:06:13</dateTime>
<version xmlns="http://www.royalmailgroup.com/integration/core/V1">1</version>
<identification xmlns="http://www.royalmailgroup.com/integration/core/V1">
<applicationId>111111113</applicationId>
<transactionId>420642961</transactionId>
</identification>
</NS1:integrationHeader>
<NS1:integrationFooter>
<errors xmlns="http://www.royalmailgroup.com/integration/core/V1">
<error>
<errorCode>E1101</errorCode>
<errorDescription>Name is a required field</errorDescription>
</error>
</errors>
</NS1:integrationFooter>
</NS1:createShipmentResponse>
</soapenv:Body>
</soapenv:Envelope>'''
def holder = new com.eviware.soapui.support.XmlHolder( xml )
holder.declareNamespace('a','http://www.royalmailgroup.com/api/ship/V1')
holder.declareNamespace('b','http://www.royalmailgroup.com/integration/core/V1' )
def errorCode = holder.getNodeValue( "//a:integrationFooter/b:errors/b:error/b:errorCode" )
assert errorCode == 'E1101'