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>
Related
Here is the code I am using:
<cfsilent>
<cffunction name="getSignatureKey" returntype="binary" access="private" output="false" hint="Derive the sign-in key">
<cfargument name="key" type="string" required="true" />
<cfargument name="dateStamp" type="string" required="true" />
<cfargument name="regionName" type="string" required="true" />
<cfargument name="serviceName" type="string" required="true" />
<cfset Local.kSecret = charsetDecode("AWS4" & arguments.key, "UTF-8") />
<cfset Local.kDate = sign( arguments.dateStamp, Local.kSecret ) />
<cfset Local.kRegion = sign( arguments.regionName, Local.kDate ) />
<cfset Local.kService = sign( arguments.serviceName, Local.kRegion ) />
<cfset Local.kSigning = sign( "aws4_request", Local.kService ) />
<cfreturn Local.kSigning />
</cffunction>
<cffunction name="sign" returntype="binary" access="private" output="false" hint="Sign with NSA SHA-256 Algorithm">
<cfargument name="message" type="string" required="true" />
<cfargument name="key" type="binary" required="true" />
<cfargument name="algorithm" type="string" default="HmacSHA256" />
<cfargument name="encoding" type="string" default="UTF-8" />
<cfset Local.keySpec = createObject("java","javax.crypto.spec.SecretKeySpec") />
<cfset Local.keySpec = Local.keySpec.init( arguments.key, arguments.algorithm ) />
<cfset Local.mac = createObject("java","javax.crypto.Mac").getInstance( arguments.algorithm ) />
<cfset Local.mac.init( Local.keySpec ) />
<cfreturn Local.mac.doFinal( charsetDecode(arguments.message, arguments.encoding ) ) />
</cffunction>
</cfsilent>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AWS Test</title>
</head>
<body>
<cfset kSecret = getSignatureKey(
'mysecretaccesskey',
'20160408',
'us-west-1',
'AWSECommerceService'
) />
<cfset MyDateTime = now()>
<cfset urlstring="http://ecs.amazonaws.com/onca/xml?AWSAccessKeyId=myaccesskeyID&Timestamp=#DateFormat(MyDateTime,"YYYY-MM-DD")#T#TimeFormat(DateAdd('h', 5 , MyDateTime),'HH:MM:SS')#Z&Signature=#BinaryEncode(kSecret, 'hex')#&BrowseNodeId=2625373011&Operation=BrowseNodeLookup&ResponseGroup=TopSellers&Service=AWSECommerceService">
<cfdump var="#urlstring#">
<CFHTTP URL="#urlstring#" result="data">
<cfdump var="#data#">
</body>
</html>
I am getting the following error from Amazon AWS:
<?xml version="1.0" ?>
<BrowseNodeLookupErrorResponse xmlns="http://ecs.amazonaws.com/doc/2005-10-05">
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message>
</Error>
<RequestId>28a54988-fda5-11e5-87c7-d5c13ae487c7</RequestId>
</BrowseNodeLookupErrorResponse>
What am I doing wrong?
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>
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"
);
I want to invoke a cfc file on my webserver, but I always get the error: The required parameter [UserID] was not provided.
Coldfusion code:
<CFINVOKE component="changeTree" method="getTreeWidth" returnVariable="httpTreeWidth">
<cfinvokeargument name="UserID" value="#checklogin.UserID#">
</CFINVOKE>
changeTree.cfc:
<CFFUNCTION name="getTreeWidth">
<CFPARAM name="UserID" required="true">
...
Thanks for help.
In changeTree.cfc, it's suppposed to be <cfargument name="UserID" required="true"> not <cfparam>.
So, I have allmost spend the night chasing a bug.... found it and no idea what is wrong.
I have script in Coldfusion which sends two emails. Both mails are in a mailer script which I'm calling with cfinvoke like so:
<cfinvoke component="form_mailer_basket" method="msg_order_seller">
... parameters
</cfinvoke>
<cfinvoke component="form_mailer_basket" method="msg_order_retailer">
... parameters
</cfinvoke>
Both mail parameters are all ok, but the 2nd mailer throws an error:
mailer orders
************************************************************************************
type: Application
************************************************************************************
message: Could not find the ColdFusion Component or Interface form_mailer_basket.
************************************************************************************
detail: Ensure that the name is correct and that the component or interface exists.
************************************************************************************
Question:
Can anyone tell me why the 2nd mail cannot find the component when the first script 5 lines above can?
Thanks!
EDIT:
Here is my code for calling both methods:
<cfif new_mail.recordcount GT 0>
<cfloop query="new_mail">
<cfset variables.newMail = new_mail.email_bestelleingang>
<cfinvoke component="form_mailer_basket" method="msg_order_seller">
<cfinvokeargument name="delDate" value="#variables.liefdatum_mail#"/>
<cfinvokeargument name="delMsg" value="#variables.bestell_text_mail#"/>
<cfinvokeargument name="delOrd" value="#LOCAL.Basket.bestelltyp#"/>
<cfinvokeargument name="mailto" value="#variables.newMail#"/>
<cfinvokeargument name="client" value="#LOCAL.Basket.re_firma#"/>
<cfinvokeargument name="rebate" value="#variables.kopf_rabatt#"/>
<cfinvokeargument name="sellerIln" value="#variables.iln_verkaeuferNEU#"/>
<cfinvokeargument name="ordNo" value="#variables.bestellnummer_neu#"/>
</cfinvoke>
</cfloop>
</cfif>
...
<cfloop query="active_check">
<cfif active_check.freigeschaltet NEQ "1" AND active_check.freigeschaltet NEQ "0">
<cfinvoke component="form_mailer_basket" method="msg_order_retailer">
<cfinvokeargument name="delDate" value="#variables.liefdatum_mail#" />
<cfinvokeargument name="delOrd" value="#LOCAL.Basket.bestelltyp#" />
<cfinvokeargument name="mailto" value="#variables.cusMail#" />
<cfinvokeargument name="client" value="#order_recipients.firma#" />
<cfinvokeargument name="rebate" value="#variables.kopf_rabatt#" />
<cfinvokeargument name="sellerIln" value="#variables.iln_verkaeuferNEU#" />
<cfinvokeargument name="ordNo" value="#variables.bestellnummer_neu#" />
<cfinvokeargument name="total" value="#variables.gesamtsumme#" />
<cfinvokeargument name="menge" value="#variables.gesamtmenge#" />
<cfinvokeargument name="curr" value="#variables.waehrung#" />
<cfinvokeargument name="agentF" value="#variables.agentFirma#" />
<cfinvokeargument name="agentN" value="#variables.agentName#" />
</cfinvoke>
</cfif>
</cfloop>
First one works, second one doesn't. Method names are correct, all parameters are ok (I know I should use an argumentsColletion...), so I'm clueless and need to take a nap. Checking back later!
And the cfc:
<cfcomponent output="false" hint="basket mailing cfc - sends out all basket related mail messages">
<!--- LOAD LANGUAGES --->
<cfinclude template="../templates/tmp_lang.cfm">
<!--- INIT --->
<cffunction name="Init" access="public" returntype="any" output="false" hint="Initialize">
<!--- nothing here for now --->
<cfreturn true />
</cffunction>
... msgs like this:
<!--- NEW ORDER SELLER --->
<cffunction name="msg_order_seller" access="public" output="false" hint="msg for new orders">
<cfargument name="delDate" type="date" required="true" hint="delivery date" />
<cfargument name="delMsg" type="string" required="true" hint="text message by retailer" />
<cfargument name="delOrd" type="string" required="true" hint="order type pre/asap" />
<cfargument name="mailto" type="string" required="true" hint="email adress" />
<cfargument name="client" type="string" required="true" hint="buyer" />
<cfargument name="rebate" type="string" required="true" hint="rebate 1/0" />
<cfargument name="sellerIln" type="string" required="true" hint="seller ILN" />
<cfargument name="ordNo" type="string" required="true" hint="order number" />
<cfprocessingdirective suppresswhitespace="No">
<cfmail
TO="#mailto#"
FROM="automailer#..."
SERVER="mail.bbb.de"
USERNAME="ddd"
PASSWORD="123456"
SUBJECT="#tx_automailer_order_new# - #client#">
#tx_automailer_default_anrede#
#tx_automailer_order_info#
#tx_automailer_order_type#: #ordertype# #rebateTxt#
#tx_automailer_order_del#: #deliveryDate#
#tx_automailer_order_no#: #ordNo#
#tx_automailer_order_date#: #DateFormat(now(),"dd.Mm.yyyy")#
#tx_kaeufer#: #client#
#tx_automailer_order_msg#:
#delMsg#
#tx_automailer_order_iln#: #sellerIln#
#tx_automailer_default_gruss#
#tx_automailer_default_team#
-------------
#tx_automailer_default_disclaimer#
</cfmail>
</cfprocessingdirective>
<cfreturn />
</cffunction>
...
</cfcomponent>
If you just want to solve your problem instead of trying to figure out what is causing it, I have a suggestion. Instead of using the cfinvoke tag for the same component many times, use either cfobject or CreateObject() to make just one instance of it. Then call the methods directly.
Even if you do get your current approach to work, it will be slower than my suggestion. cfinvoke creates an object each time you call it and that takes processing time.
Are you sure that both methods exist and are public?
Using cfinclude in cfc is NOT good practice, though admittedly I had to do it too on occasions.
Your error Could not find the ColdFusion Component or Interface form_mailer_basket seems to imply that something happens to the component itself - I suspect it has something to do with your return statement in Init() method.
In earlier versions of CF (I think around version 6/7 maybe 8) you could overwrite your function by setting identically named variable inside your cfc. You did not mention the CF version that you are running.