I am trying to consume an api and trying to convert this code to codfusion
<?php
$client = new SoapClient(
"http://trial.black011.com/retailer/Black011SvcDemo.wsdl”,
array( "trace" => 1,
"exceptions" => 0)
);
try {
$arr = $client->recharge( ‘TestID, "TestPassword", "BKLD", “1234567890”,
10, "Any Comment1 of You" );
echo 'error_code' . $arr['error_code'];
echo 'error_msg' . $arr['error_msg'];
echo 'tx_id' . $arr['tx_id'];
echo 'comment1' . $arr['comment1'];
}catch (SoapFault $exception) {
echo "Error Code:" . $exception->getCode();
echo "Error Message:" . $exception->getMessage();
}
?>
I am using below code to consume the api
<cfinvoke webservice="http://trial.black011.com/retailer/Black011SvcDemo.wsdl" method="recharge" returnvariable="res" refreshwsdl="true" >
<cfinvokeargument name="user_id" value="TestID">
<cfinvokeargument name="passwd" value="TestPassword">
<cfinvokeargument name="prod_id" value="BKLD">
<cfinvokeargument name="mdn" value="1112223333">
<cfinvokeargument name="amount" value="10">
<cfinvokeargument name="comment1" value="10">
</cfinvoke>
I also tried this-
<cfscript>
ws = createObject("webservice", "http://trial.black011.com/retailer/Black011SvcDemo.wsdl");
writeDump(ws);
result = ws.recharge( "TestID", "TestPassword", "BKLD", "19112223333", 10.00 );
writeDump(result);
</cfscript>
But every time I am trying, getting below error-
Web service operation recharge with parameters {} can not be found.
Could anybody see any problem with my code?
I have a code and seems to be working as I tested it.
<cfsavecontent variable="soapBody">
<cfoutput>
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:black011">
<soapenv:Header/>
<soapenv:Body>
<urn:recharge soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<user_id xsi:type="xsd:string">test</user_id>
<passwd xsi:type="xsd:string">twawd</passwd>
<prod_id xsi:type="xsd:string">"BKLD"</prod_id>
<mdn xsi:type="xsd:string">"1234567890"</mdn>
<amount xsi:type="xsd:float">20.0</amount>
<comment1 xsi:type="xsd:string">"test"</comment1>
</urn:recharge>
</soapenv:Body>
</soapenv:Envelope>
</cfoutput>
</cfsavecontent>
<cfhttp url="http://trial.black011.com/retailer/OpenSvc.php" method="post" result="httpResponse">
<cfhttpparam type="header" name="SOAPAction" value="http://trial.black011.com/retailer/OpenSvc.php/recharge" />
<cfhttpparam type="header" name="accept-encoding" value="no-compression" />
<cfhttpparam type="xml" value="#trim( soapBody )#" />
</cfhttp>
<cfif find( "200", httpResponse.statusCode )>
<cfset soapResponse = xmlParse( httpResponse.fileContent ) />
<cfdump var="#soapResponse#">
</cfif>
Look at ws variable dump, method recharge takes 9 parameters:
recharge(java.lang.String,
java.lang.String,
java.lang.String,
java.lang.String,
float,
javax.xml.rpc.holders.StringHolder,
javax.xml.rpc.holders.StringHolder,
javax.xml.rpc.holders.StringHolder,
javax.xml.rpc.holders.StringHolder) returns void
Seems the code below works fine:
<cfscript>
wsargs = {};
wsargs.refreshwsdl = "Yes";
ws = createObject("webservice",
"http://trial.black011.com/retailer/Black011SvcDemo.wsdl",
wsargs);
result = ws.recharge("TestID",
"TestPassword",
"BKLD",
"19112223333",
10.0,
"test",
"test",
"test",
"test");
</cfscript>
Hope this could help
In your question you state you are specifing the method as follows
result = ws.recharge( "TestID", "TestPassword", "BKLD", "19112223333", 10.00 );
Which has 5 arguments. The WSDL reads
<message name="rechargeRequest">
<part name="user_id" type="xsd:string"/>
<part name="passwd" type="xsd:string"/>
<part name="prod_id" type="xsd:string"/>
<part name="mdn" type="xsd:string"/>
<part name="amount" type="xsd:float"/>
<part name="comment1" type="xsd:string"/>
</message>
There are 6 arguments. You need to specify something for the 6th arguments, as typically with WSDLs the arguments help define the function in the same way as the function name does. There aren't any optional arguments. This gives the following which should work
result = ws.recharge(
"TestID",
"TestPassword",
"BKLD",
"19112223333",
10.00,
"Some comment here"
);
Related
Here is the XML format that I'm trying to create a web service for:
<test a1="a1">
<e1>e1</e1>
<e2 a2="a2">
<e3>e3</e3>
<e3>e3</e3>
</e2>
</test>
My problem is that I don't know how to create a Coldfusion (cfcomponent) SOAP web service that would conform to the XML format.
This is what I have come up with:
<cfcomponent style="document" wsversion = 1 >
<cffunction name="test" returntype="String" access="remote">
<cfargument type="String" required="no" name="e1"/>
<cfargument type="xml" required="no" name="e2" />
<cfreturn "ok">
</cffunction>
</cfcomponent>
As you can see, a1,a2 and e3 are left out as I have no idea how to define them in the cffunction, and I'm not sure if making e2 as xml type is correct.
Any help is appreciated.
you have to use
<cfsavecontent variable="textxml">
<cfoutput>
<test a1="a1">
<e1>e1</e1>
<e2 a2="a2">
<e3>e3</e3>
<e3>e3</e3>
</e2>
</test>
</cfoutput>
</cfsavecontent>
and pass the testxml variable to the function as xml type argument.
<cfinvoke method="test" component="compname" xmltest="#textxml#">
no need to send seperate arguments e1 e2...can send testxml variable to the function.
<cfcomponent >
<cffunction name="test" returntype="String" access="remote">
<cfargument type="xml" required="no" name="xmltest" />
<cfset newXML = XMLParse(arguments.xmltest)>
<cfdump var="#newXML#">
<cfreturn "ok">
</cffunction>
</cfcomponent>
Here is a SOAP request example:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ws="http://ws_test">
<soapenv:Header/>
<soapenv:Body>
<ws:testService a1="a1" a2="a2">
<ws:e1>e1</ws:e1>
<ws:e2>e2</ws:e2>
</ws:testService>
</soapenv:Body>
</soapenv:Envelope>
And here is my example cfc web service:
<cfcomponent style="document" wsversion = 1>
<cffunction name="testService" returntype="String" access="remote" >
<cfargument type="string" name="e1"/>
<cfargument type="string" name="e2"/>
<!--- Missing: code to extract a1 and a2 --->
<cfreturn "#e1# #e2#">
</cffunction>
</cfcomponent>
I'm new to Coldfusion and web service, and I have no idea on how to extract attributes a1 and a2 from <testService>, googled it but can't find any reference. Any ideas?
=== Edit ===
Thought it might be useful if I attach the type definition:
<complexType name="testServiceType">
<sequence>
<element name="e1" type="string"></element>
<element name="e2" type="string"></element>
</sequence>
<attribute name="a1" type="string"/>
<attribute name="a2" type="string"/>
</complexType>
Note that although this is my test web service, but it is based on a data schema that is provided by our partner, which means my web service has to conform with it.
=== Resolution ===
Based on Gerry's answer, this is what I ended up doing:
<cfcomponent style="document" wsversion = 1>
<cffunction name="testService" returntype="String" access="remote" >
<cfargument type="string" name="e1"/>
<cfargument type="string" name="e2"/>
<cfset soapReq = getSOAPRequest()>
<cfset soapXML = xmlParse(soapReq)>
<cfset attributes = soapXML.Envelope.body.XmlChildren[1].XmlAttributes>
<cfset a1 = attributes.a1>
<cfset a2 = attributes.a2>
<cfreturn "#e1# #e2# #a1# #a2#">
</cffunction>
</cfcomponent>
Based on your comment, I think you need getSoapRequest() and then parse it using the code from the answer given by keshav-jha
<cfcomponent style="document" wsversion = 1>
<cffunction name="testService" returntype="String" access="remote" >
<cfargument type="string" name="e1"/>
<cfargument type="string" name="e2"/>
<cfscript>
soapReq=GetSOAPRequest();
soapXML=xmlParse(soapReq);
bodyAttributes = {
a1:soapXML.Envelope.body.XmlChildren[1].XmlAttributes.a1
,a2:soapXML.Envelope.body.XmlChildren[1].XmlAttributes.a2
};
return serializejson(bodyAttributes);
</cfscript>
</cffunction>
</cfcomponent>
You just need to parse your XML and then get the value of a1 and a2
<cfsavecontent variable="myXML" >
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws_test">
<soapenv:Header/>
<soapenv:Body>
<ws:testService a1="a1" a2="a2">
<ws:e1>e1</ws:e1>
<ws:e2>e2</ws:e2>
</ws:testService>
</soapenv:Body>
</soapenv:Envelope>
</cfsavecontent>
<cfset parXML = xmlParse(myXML) />
<cfdump var="#parXML.Envelope.body.XmlChildren[1].XmlAttributes.a1#">
If you are creating the web service, then you have complete control over how the webservice is consumed. In this case a1 and a2 are not ever passed into the CFC for processing. So if they have meaning, you can set them up as parameters like e1 and e2.
One of the best tools I've ever used for understanding and using web services is SoapUI. If you create the example.cfc and point SOAPUI at it, you will get an XML request that looks like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://soap.stack">
<soapenv:Header/>
<soapenv:Body>
<soap:testService>
<soap:e1>e1</soap:e1>
<soap:e2>e2</soap:e2>
</soap:testService>
</soapenv:Body>
</soapenv:Envelope>
If you want to process a1 and a2, there is no reason not to handle them as regular arguments.
So you could make a CFC that looks like this:
<cfcomponent style="document" wsversion = 1>
<cffunction name="testService" returntype="String" access="remote" >
<cfargument type="string" name="a1"/>
<cfargument type="string" name="a2"/>
<cfargument type="string" name="e1"/>
<cfargument type="string" name="e2"/>
<cfset var ret=serializeJSON(arguments) />
<cfreturn "#ret#">
</cffunction>
</cfcomponent>
And if you point SOAPUI at it, then it will generate a SOAP envelope that looks like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://soap.stack">
<soapenv:Header/>
<soapenv:Body>
<soap:testService>
<soap:a1>?</soap:a1>
<soap:a2>?</soap:a2>
<soap:e1>?</soap:e1>
<soap:e2>?</soap:e2>
</soap:testService>
</soapenv:Body>
</soapenv:Envelope>
I'm trying build a custom XML file and splitting the building into separate functions, but I'm having trouble doing this with cfxml. This example is obviously simplified.
This works fine:
<cfcomponent accessors="true">
<cfproperty name="Name" />
<cfproperty name="Model" />
<cfproperty name="Make" />
<cffunction name="BuildCarXML" output="false">
<cfsavecontent variable="xmlCar">
<cfoutput>
<?xml version="1.0" encoding="UTF-8" ?>
<car>
<name>#variables.Name#</name>
#AddMakeElement()#
</car>
</cfoutput>
</cfsavecontent>
<cfreturn xmlCar />
</cffunction>
<cffunction name="AddMakeElement">
<cfsavecontent variable="xmlMake">
<cfoutput>
<make>Something</make>
</cfoutput>
</cfsavecontent>
<cfreturn xmlMake />
</cffunction>
</cfcomponent>
But this produces an XML string with spaces:
<?xml version="1.0" encoding="UTF-8" ?> <car> <name>Ferrari</name> <make>Something</make> </car>
If I use cfxml, or even do an XMLParse() on the cfreturn of BuildCarXML, i get the following error:
An error occured while Parsing an XML document.
The processing instruction target matching "[xX][mM][lL]" is not allowed.
Is it possible to do this using cfxml?
In AddMakeElement(), if you use <cfxml> and toString(), the output is:
<?xml version="1.0" encoding="UTF-8"?> <make>Something</make>
Therefore it couldn't be embedded into your xmlCar. So for AddMakeElement(), keep using <cfsavecontent>, or just return "<make>Something</make>".
I am new to ColdFusion and need to write code to consume a SOAP based web service.
Any links/pointers/examples for consuming SOAP based web service which has complex types will help.
When I am writing the code to consume the below web service in ColdFusion, how should I handle operation name, input msg, and complex types? Just need some pointers to get started.
XSD is something like :
<!-- S Request -->
<xs:complexType name="SRequestHeader">
+ <xs:sequence>
+ <xs:element name="sID" minOccurs="1" maxOccurs="1"> </xs:element>
+ <xs:element name="orderNumber" minOccurs="1" maxOccurs="1"> </xs:element>
+ <xs:element name="dateCreated" minOccurs="1" maxOccurs="1"> </xs:element>
</xs:complexType>
- <xs:complexType name="SOrderLine">
- <xs:sequence>
- <xs:element name="lineNumber" minOccurs="1" maxOccurs="1"> </xs:element>
- <xs:element name="recordType" minOccurs="1" maxOccurs="1"> </xs:element>
- <xs:element name="dueDate" minOccurs="1" type="xs:dateTime" />
</xs:complexType>
......
WSDL has :
<WL:portType name="SPortType">
- <WL:operation name="newOrder">
<WL:input message="WL:newOrderRequest" name="newOrderRequest" />
<WL:output> message="W:newOrderResponse" name="newOrderResponse" />
<WL:fault> message="WL:WSException" name="WSException" />
</WL:operation>
I am using something like:
<soapenv:Body>
<newOrder>
<soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<sor:newOrderRequest>
<sor:SOrderRequest>
<sor:sID>S123</sor:sID> ....
And finally...
<cfhttp url="http://xxxx:123/YYY/SService" method="post" timeout="118"
throwonerror="yes">
<cfhttpparam type="header" name="content-type" value="text/xml">
<cfhttpparam type="header" name="SOAPAction" value="">
<cfhttpparam type="header" name="content-length" value="#len(soap)#">
<cfhttpparam type="header" name="charset" value="utf-8">
<cfhttpparam type="xml" name="message" value="#trim(soap)#">
</cfhttp>
Getting 500 Internal Server Error on this line :
<cfhttpparam type="xml" name="message" value="#trim(soap)#">
You have not shared complete code so some assumptions must be made.
Ben Nadel has a wonderful write up on this topic. You should definitely read this first: Making SOAP Web Service Requests With ColdFusion And CFHTTP
Whenever I interact with SOAP services I usually end up using something similar to the following. It is very similar to the code fragment that you shared but you did not show (among other things) the content being wrapped in <cfsavecontent> tags to store the XML in the soap variable before making the <cfhttp> request. This could be your problem? The following is just an example to get you going.
<cfsavecontent variable="soap">
<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">
<soapenv:Header/>
<soapenv:Body>
<ns1:newOrder xmlns:ns1="urn:TripFlow" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<sID>001</sID>
<orderNumber>12345</orderNumber>
<dateCreated>07/31/2013</dateCreated>
</ns1:newOrder>
</soapenv:Body>
</soapenv:Envelope>
</cfsavecontent>
<!--- Invoke web service to send message--->
<cfhttp url="http://xxxx:123/YYY/SService" method="post" timeout="10">
<cfhttpparam type="header" name="content-type" value="text/xml" />
<cfhttpparam type="header" name="SOAPAction" value="""SService-method-name-here""" />
<!---<cfhttpparam type="header" name="accept-encoding" value="no-compression" /> sometimes this is needed --->
<cfhttpparam type="header" name="content-length" value="#len(soap)#" />
<cfhttpparam type="header" name="charset" value="utf-8" />
<cfhttpparam type="xml" name="message" value="#trim(soap)#" />
</cfhttp>
Another invaluable tool when working with web services is soapUI. That should definitely be a part of your toolkit as well. You can build your request using soapUI and check the responses. Once you have it working with soapUI you can copy your request into your ColdFusion code.
Thanks #Miguel-F .Finally used SOAPUI and understood what was going wrong.
Had set parameter throwonerror="Yes" .Because of this ParseException was going to error block rather than getting captured in code.
On setting throwonerror="No", the code finally started working and reading the response tags.
The following is a sample SOAP 1.2 request and response. The placeholders shown need to be replaced with actual values.
POST /CommunicationOfficeService1_0/CompanyAccountXmlService.asmx HTTP/1.1
Host: webservices.nbs.rs
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Header>
<AuthenticationHeader xmlns="http://communicationoffice.nbs.rs">
<UserName>string</UserName>
<Password>string</Password>
<LicenceID>guid</LicenceID>
</AuthenticationHeader>
</soap12:Header>
<soap12:Body>
<GetCompanyAccountByNationalIdentificationNumber xmlns="http://communicationoffice.nbs.rs">
<nationalIdentificationNumber>long</nationalIdentificationNumber>
</GetCompanyAccountByNationalIdentificationNumber>
</soap12:Body>
</soap12:Envelope>
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetCompanyAccountByNationalIdentificationNumberResponse xmlns="http://communicationoffice.nbs.rs">
<GetCompanyAccountByNationalIdentificationNumberResult>string</GetCompanyAccountByNationalIdentificationNumberResult>
</GetCompanyAccountByNationalIdentificationNumberResponse>
</soap12:Body>
</soap12:Envelope>
I have generated the ColdFusion code that looks like this
<cfsavecontent variable="soapBody">
<cfoutput>
POST /CommunicationOfficeService1_0/CompanyAccountXmlService.asmx HTTP/1.1
Host: webservices.nbs.rs
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Header>
<AuthenticationHeader xmlns="http://communicationoffice.nbs.rs">
<UserName>my_username</UserName>
<Password>my_password</Password>
<LicenceID>My_licence_id</LicenceID>
</AuthenticationHeader>
</soap12:Header>
<soap12:Body>
<GetCompanyAccountByNationalIdentificationNumber xmlns="http://communicationoffice.nbs.rs">
<nationalIdentificationNumber>20774550</nationalIdentificationNumber>
</GetCompanyAccountByNationalIdentificationNumber>
</soap12:Body>
</soap12:Envelope>
</cfoutput>
</cfsavecontent>
<!---
Now that we have our SOAP body defined, we need to post it as
a SOAP request to the Campaign Monitor website. Notice that
when I POST the SOAP request, I am NOT required to append the
"WSDL" flag to the target URL (this is only required when you
actually want to get the web service definition).
--->
<cfhttp
url="https://webservices.nbs.rs/CommunicationOfficeService1_0/CompanyAccountXmlService.asmx"
method="post"
result="httpResponse">
<!---
Most SOAP action require some sort of SOAP Action header
to be used.
--->
<cfhttpparam
type="header"
name="SOAPAction"
value="http://communicationoffice.nbs.rs/GetCompanyAccountByNationalIdentificationNumber"
/>
<!---
I typically use this header because CHTTP cannot handle
GZIP encoding. This "no-compression" directive tells the
server not to pass back GZIPed content.
--->
<cfhttpparam
type="header"
name="accept-encoding"
value="no-compression"
/>
<!---
When posting the SOAP body, I use the CFHTTPParam type of
XML. This does two things: it posts the XML as a the BODY
and sets the mime-type to be XML.
NOTE: Be sure to Trim() your XML since XML data cannot be
parsed with leading whitespace.
--->
<cfhttpparam
type="xml"
value="#trim( soapBody )#"
/>
</cfhttp>
<!---
When the HTTP response comes back, our SOAP response will be
in the FileContent atribute. SOAP always returns valid XML,
even if there was an error (assuming the error was NOT in the
communication, but rather in the data).
--->
<cfif find( "200", httpResponse.statusCode )>
<!--- Parse the XML SOAP response. --->
<cfset soapResponse = xmlParse( httpResponse.fileContent ) />
<!---
Query for the response nodes using XPath. Because the
SOAP XML document has name spaces, querying the document
becomes a little funky. Rather than accessing the node
name directly, we have to use its local-name().
--->
<cfset responseNodes = xmlSearch(
soapResponse,
"//*[ local-name() = 'Subscriber.AddAndResubscribeResult' ]"
) />
<!---
Once we have the response node, we can use our typical
ColdFusion struct-style XML node access.
--->
<cfoutput>
Code: #responseNodes[ 1 ].Code.xmlText#
<br />
Success: #responseNodes[ 1 ].Message.xmlText#
</cfoutput>
</cfif>
I have none results . The web service uses this is the web site
This is the wsdl file
Serbian National Bank Web Service
How to make this web service run
I've modified a function I've used in the past to pass data form ColdFusion to Dynamics GP via soap.
<cffunction name="callWebService" access="public" output="false">
<cfargument name="soap" type="xml" required="true">
<cfhttp url="https://webservices.nbs.rs/CommunicationOfficeService1_0/CompanyAccountXmlService.asmx" method="post">
<cfhttpparam type="header" name="content-type" value="application/soap+xml">
<cfhttpparam type="header" name="SOAPAction" value="http://communicationoffice.nbs.rs/GetCompanyAccountByNationalIdentificationNumber">
<cfhttpparam type="header" name="accept-encoding" value="no-compression">
<cfhttpparam type="header" name="content-length" value="#len(Arguments.soap)#">
<cfhttpparam type="header" name="charset" value="utf-8">
<cfhttpparam type="xml" name="message" value="#trim(Arguments.soap)#">
</cfhttp>
<cfreturn Trim(cfhttp.FileContent)>
</cffunction>
I believe I've updated the <cfhttpparam />s necessary for the web service you've linked. I would recommend using a software called SOAP UI to test your connection to the service and SOAP XML body outside of ColdFusion. In my above function, the argument soap would be your saved content "soapBody".
One thing needs to be fixed in your soapBody. The text prior to the start of XML is information regarding data that needs to be in the HTTP header, and I've only seen these values imputed as <cfhttpparam />.
The reason I think you may not be getting the desired 200 response with your above code is that the XML body is incorrectly formatted with the WSDL HTTP header example text. I also did not see the length of the body being declared as well.
While trying to set up your connection try just dumping httpResponse out until you start seeing valid soap responses from the server.