Coldfusion WCF api implementation - wcf

Below is the example of calling API that I got from Provider, I am facing problem converting this code to coldfusion. Any help will be appriciated
var parameters = new List<RegaloPayBillerFieldWithValue>
{
new RegaloPayBillerFieldWithValue
{
Name = "NPE",
Value = "1234567890"
}
};
var preReceipt = client.RegaloPayPreReceipt(accessId: "2FC60D63-9091-4530-BC08-AF0D5742BBF2", billerPublicId: 3, localAmount: 0, billParameters: parameters);
The part where I am facing the problem is the upper part i.e.
var parameters = new List<RegaloPayBillerFieldWithValue>
{
new RegaloPayBillerFieldWithValue
{
Name = "NPE",
Value = "1234567890"
}
};
Two variables here i.e. Name and value are not being posted correctly.Test url is http://regalocashservice.cloudapp.net:8085/RegaloCashService.svc?wsdl

You could write-
<cfset wsdlurl = "http://regalocashservice.cloudapp.net:8085/RegaloCashService.svc?wsdl">
<cfset parameters = StructNew()>
<cfset RegaloPayBillerField = ArrayNew(1)>
<cfset vars = structNew()>
<cfset ArrayAppend(RegaloPayBillerField, {Name="NPE", Value="1234567890"})>
<cfset StructAppend(parameters, {RegaloPayBillerFieldWithValue = RegaloPayBillerField })>
<cfset vars["billerPublicId"] = 2>
<cfset vars["localAmount"] = 0>
<cfset vars["accessId"] = "2FC60D63-9091-4530-BC08-AF0D5742AAF2">
<cfinvoke webservice="#wsdlurl#" method="RegaloPayPreReceipt" returnVariable="res" argumentcollection="#vars#" >
<cfinvokeargument name="billParameters" value="#parameters#"/>
</cfinvoke>
<cfdump var="#res.getResponseCode()#">

var parameters = new List<RegaloPayBillerFieldWithValue>
{
new RegaloPayBillerFieldWithValue
{
Name = "NPE",
Value = "1234567890"
}
};
From the example, and WSDL, it looks like they are just creating an array of structures, which is then passed via a wrapper object ie another structure. I think it should work if you create the array, then wrap it like so:
<cfscript>
// create ArrayOfRegaloPayBillerFieldWithValue wrapper object
parameters = [ {Name="NPE", Value="1234567890"} ];
billParameters = { RegaloPayBillerFieldWithValue=parameters };
// create web service
ws = createObject("webservice", "http://regalocashservice.cloudapp.net:8085/RegaloCashService.svc?wsdl");
// debug
writeDump(ws);
// get result code
result = ws.RegaloPayPreReceipt( "2FC60D63-9091-4530-BC08-AF0D5742AAF2"
, 3 , 0, billParameters );
writeDump(result.getResponseCode());
</cfscript>

Note: the code below was tested in CF 11 Dev Edition environment
<cftry>
<cfset parameters = StructNew()>
<cfset StructAppend(parameters, {Name="NPE", Value="1234567890"})>
<cfinvoke webservice="test" method="RegaloPayPreReceipt" returnVariable="res">
<cfinvokeargument name="accessId" value="REAL_ACCESSID_HERE"/>
<cfinvokeargument name="billerPublicId" value="3"/>
<cfinvokeargument name="localAmount" value="0"/>
<cfinvokeargument name="billParameters" value="#parameters#"/>
</cfinvoke>
<cfdump var="#res#">
<cfcatch type="Any">
<cfdump var="#cfcatch.message#">
</cfcatch>
</cftry>
Web Service "test" is mapped to http://regalocashservice.cloudapp.net:8085/RegaloCashService.svc?wsdl in CF Admin Tool. Here is dump of the object returned org.datacontract.schemas._2004._07.domainclasses_dtos_results.RegaloPayPreReceiptResult

Related

Kraken API - ColdFusion

Trying to tackle the Kraken API. Using ColdFusion 2016.
I have a few tries in here, but can't seem to quite get it.
So testing message, message2, message3 attempts.
https://docs.kraken.com/rest/#section/Authentication/Headers-and-Signature
HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
EXPECTED RESULT:
4/dpxb3iT4tp/ZCVEwSnEsLxx0bqyhLpdfOpc6fn7OR8+UClSV5n9E6aSS8MPtnRfp32bAb0nmbRn6H8ndwLUQ==
<cfset _key = "APIKEY">
<cfset _s = "kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F">
<cfset nonce = "1616492376594">
<cfset payload = "nonce=1616492376594&ordertype=limit&pair=XBTUSD&price=37500&type=buy&volume=1.25">
<cfset URIPath = "/0/private/AddOrder">
<cfscript>
apiKey = "#_key#";
apiSecret = "#_s#";
theKeyBytes = charsetDecode(#_s#, "UTF-8");
_Secret64 = toBase64(#_s#);
// get_kraken_signature(urlpath, data, secret):
h = '#uripath#' & #payload#;
_hash = hmac(h, theKeyBytes, "HMACSHA256");
//HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
//SHA256(nonce + POST data))
_256 = hmac(payload, "HMACSHA256");
_sign = hmac(payload, theKeyBytes, "HMACSHA256");
// HMAC-SHA512 of (URI path + SHA256(nonce + POST data))
message = '#uripath#' & #_256#;
message2 = '#uripath#' & #_256# & #_Secret64#;
message3 = '#uripath#' & #_sign# & #_Secret64#;
_512 = hmac(#message#, "HMACSHA512");
_512_2 = hmac(#message2#, "HMACSHA512");
_512_3 = hmac(#message3#, "HMACSHA512");
_512_H = hmac(#_hash#, "HMACSHA512");
S_H = hmac(#_512_h#, #_s#, "HmacSHA512");
H64 = toBase64(binaryDecode(#s_h#, "hex"));
// base64 decoded secret API key
_64 = toBase64(#_512#);
S_Hex = hmac(#_512#, #_s#, "HmacSHA512");
Hex64 = toBase64(binaryDecode(#s_hex#, "hex"));
S_Hex2 = hmac(#_512_2#, #_s#, "HmacSHA512");
Hex642 = toBase64(binaryDecode(#s_hex2#, "hex"));
S_Hex3 = hmac(#_512_3#, #_s#, "HmacSHA512");
Hex643 = toBase64(binaryDecode(#s_hex3#, "hex"));
</cfscript>
EXPECTED RESULT:
4/dpxb3iT4tp/ZCVEwSnEsLxx0bqyhLpdfOpc6fn7OR8+UClSV5n9E6aSS8MPtnRfp32bAb0nmbRn6H8ndwLUQ==
Hex64 Gets:
w1PXl7IDLs1Pri1Vf++UcLFWIFedkxgpceFVkVFbxt7wvjj/Q0wtwwLSMJxV7bMOdFi+BEN3lHuX+CWRx2SxAQ==
Hex642 Gets:
Zxd+96KuI3wSQJ/b0l79djB1M7FMsczoWOfs9Ha5YWIC6sc6uryEGn4MgkcHnF/ndsxDQ2y/jSHl0RxTIuc7PA==
Hex643 Gets:
5KCKhgRGexBPF7SgnSB5G0m3bu+2ecf4fAOndDG0pvYLh0PeWC1nWodi5szigcGU4TyLLb80jPNAR7OmK0t0Sw==
Taking this question as an exercise, I've managed to translate the python function from KrakenAPI docs to CFML script. That function should help you and others with a practical solution. Also publishing it here for my own documentation:
<cfscript>
public string function getKrakenSignature( urlpath, postdata, nonce, secretAsBase64) localmode=true {
// assign arguments to local variables
urlpath= arguments.urlpath;
nonce= arguments.nonce;
postdata = arguments.postdata;
secretAsBase64= arguments.secretAsBase64;
// convert urlpath to a binary Hex representation
urlpathBinary= toBinary( toBase64( urlpath ));
urlpathBinaryAsHex= BinaryEncode( urlpathBinary, "HEX");
// convert secret to binary
secretBinary= ToBinary( arguments.secretAsBase64 );
// concatenate nonce and postdata
noncePostdata = nonce & postdata;
//get binary digest as Hex representation
noncePostdataDigestBinaryAsHex= hash( noncePostdata, "SHA-256" );
// concatenate urlPath binary (hex) and oncePostdataDigest binary (hex)
messageBinaryAsHex= urlpathBinaryAsHex & noncePostdataDigestBinaryAsHex;
// convert message hex representation to binary
messageBinary= BinaryDecode( messageBinaryAsHex, "HEX");
// sign the message with hmac function
messageHmacDigestBinaryAsHex = hmac( messageBinary, secretBinary, "HMACSHA512");
messageHmacDigestBinary=BinaryDecode( messageHmacDigestBinaryAsHex, "HEX");
return binaryEncode( messageHmacDigestBinary, "base64" );
}
encodedPayLoad="nonce=1616492376594&ordertype=limit&pair=XBTUSD&price=37500&type=buy&volume=1.25";
nonce="1616492376594";
api_sec = "kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F1huXg==";
urlpath="/0/private/AddOrder";
signature = getKrakenSignature( urlpath, encodedPayLoad, nonce, api_sec);
writeoutput( signature );
</cfscript>
Find a gist here at tryCf.com
Yes answer above works.
Arrrgh - I had the wrong Secret Key - Cut Paste issue. I only figured it out when reversing the secretkey - that script below as well
kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F
vs
kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F1huXg==
Credit AndreasRu above for that answer and method.
I am posting another method below. I have used this one for most of the Crypto API's.
HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
<cfset _key = "APIKEY">
<cfset _s = "kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F1huXg==">
<cfset nonce = "1616492376594">
<cfset payload = "nonce=1616492376594&ordertype=limit&pair=XBTUSD&price=37500&type=buy&volume=1.25">
<cfset URIPath = "/0/private/AddOrder">
<cfscript>
// URIPATH to a binary Hex
BURL64 = toBinary(toBase64(#URIPath#));
URLHEX = BinaryEncode(BURL64,"HEX");
// Secret to binary
SB = ToBinary(#_s#);
// SHA256(nonce + POST data)
SHA256_Post = '#nonce#' & #payload#;
SHA_256 = hash(#SHA256_Post#, "SHA-256", "UTF-8");
// BUILD SHA-512
URI256POST = '#urlhex#' & #SHA_256#;
// convert SHA512 buid to message hex
MESSAGEHEX = BinaryDecode(URI256POST,"HEX");
// messageHex to HMAC SHA-512
M512 = hmac(#MESSAGEHEX#, #SB#, "HMACSHA512");
M512HEX = BinaryDecode(M512,"HEX");
// Final Signature
SignFinal = toBase64(M512HEX);
</cfscript>
<cfoutput>
EXPECTED RESULT:
4/dpxb3iT4tp/ZCVEwSnEsLxx0bqyhLpdfOpc6fn7OR8+UClSV5n9E6aSS8MPtnRfp32bAb0nmbRn6H8ndwLUQ==
#signfinal#
</cfoutput>
Figuring out secret code below. Not needed for Kraken API-Sign
<cfscript>
hexEncoded = binaryEncode(secretBinary, "hex");
base64Encoded = binaryEncode(secretBinary, "base64");
writeDump
([
secretBinary,
hexEncoded,
base64Encoded,
binaryDecode(hexEncoded, "hex"),
binaryDecode(base64Encoded, "base64")
]);
</cfscript>

Failing to write the query results to a csv file ColdFusion

I put my project on a new server where I am using ColdFusion 2016 but it is failing while running the following lines:
<cfset fastFileWriter = createObject("java", "FastResultsetToFile")>
<cfset fastFileWriter.exportResultsetToFile(myQuery, "#TempFile#", ',', "UTF-8")>
In ColdFusion 9, where my old server is, it is working just fine. Does anyone knows why this is happening and how to make this work for ColdFusion 2016?
Here is a bigger picture of the code:
<cfset yopath = "#application.masterpath#/platform_a/reports/pods/#pid#" />
<cfset acfile = "outbound_export_#session.callmeasurement_uid#.csv" />
<cfset TempFile = "#yopath#/#acfile#">
<cfif FileExists(TempFile)>
<cffile action="delete" file="#TempFile#" >
</cfif>
<cfset myQuery = QueryNew("Team_Member, Calls, Unique, Live_Connections, Rescued_Calls")>
<cfloop query = "pull_staff">
<cfset newrow = QueryAddRow(myQuery,1)>
<cfset temp = QuerySetCell(myQuery, 'Team_Member', #lename#)>
<cfset temp = QuerySetCell(myQuery, 'Calls', #all_calls#)>
<cfset temp = QuerySetCell(myQuery, 'Unique', #unique_calls#)>
<cfset temp = QuerySetCell(myQuery, 'Live_Connections', #live_convo#)>
<cfset temp = QuerySetCell(myQuery, 'Rescued_Calls', #rescued#)>
</cfloop>
<!--- The code is running just fine up to this point. I used a cfdump to check the query "pull_staff" and it is returning the right results with correct column names --->
<cfset fastFileWriter = createObject("java", "FastResultsetToFile")>
<cfset fastFileWriter.exportResultsetToFile(myQuery, "#TempFile#", ',', "UTF-8")>
I expect it has something to do with a missing Java dependency on the new server
<cfset fastFileWriter = createObject("java", "FastResultsetToFile")>
For this to work it requires that the FastResultsetToFile class (or related JAR) is in one of the directories that ColdFusion uses for its classpath, otherwise it will never run.

Intuit API OAuth ApplicationAuthenticationFailed; errorCode=003200

I am using this library for OAuth v1.0 to connect to QuickBooks Online API. I am successfully able to use three legged authentication and get back access tokens. I am also able to do connect to most endpoints with no problem. However, I am having issue connecting to endpoints with URL parameters.
For example, this URL returns with no issue:
https://sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/customer/8
However, this URL returns with SignatureBaseString: error 401 unAuthorized.
//sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/query?query=select * from customer
Am I misunderstanding something about how to access endpoints with URL parameters in OAuth? Any help or insight would be appreciated.
Working Code:
<cfset oAuthRequest = new com.brianflove.oauth.Request()>
<cfset oAuthConsumer = new com.brianflove.oauth.Consumer()>
<cfset oauthConsumer.setSecret(CONSUMER_SECRET)>
<cfset oauthConsumer.setKey(CONSUMER_KEY)>
<cfset oAuthRequest.setMethod("GET")>
<cfset oAuthRequest.setUrl("https://sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/customer/" & randrange(1,8))>
<cfset oAuthRequest.setConsumer(oAuthConsumer)>
<cfset oAuthRequest.setToken(session.token)>
<!---use HMAC-SHA1 signature method--->
<cfset signatureMethod = new com.brianflove.oauth.methods.HmacSha1SignatureMethod()>
<!---sign request--->
<cfset oAuthRequest.signWithSignatureMethod(signatureMethod=signatureMethod)>
<!---POST using request URL--->
<cfset httpRequest = new Http()>
<cfset httpRequest.setUrl(oAuthRequest.getUrl())>
<cfset httpRequest.setMethod(oAuthRequest.getMethod())>
<cfset httpRequest.addParam(type="header", name="Authorization", value=oAuthRequest.toHeader())>
<cfset httpRequest.addParam(type="header", name="Accept", value="application/json") />
<cfset httpRequest.setCharset("utf-8")>
<cfset httpResult = httpRequest.send().getPrefix()>
<cfdump var="#httpResult.filecontent#">
Not Working Code:
<cfset oAuthRequest = new com.brianflove.oauth.Request()>
<cfset oAuthConsumer = new com.brianflove.oauth.Consumer()>
<cfset oauthConsumer.setSecret(CONSUMER_SECRET)>
<cfset oauthConsumer.setKey(CONSUMER_KEY)>
<cfset oAuthRequest.setMethod("GET")>
<cfset oAuthRequest.setUrl("https://sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/query?query=select * from customer") />
<cfset oAuthRequest.setConsumer(oAuthConsumer)>
<cfset oAuthRequest.setToken(session.token)>
<!---use HMAC-SHA1 signature method--->
<cfset signatureMethod = new com.brianflove.oauth.methods.HmacSha1SignatureMethod()>
<!---sign request--->
<cfset oAuthRequest.signWithSignatureMethod(signatureMethod=signatureMethod)>
<!---POST using request URL--->
<cfset httpRequest = new Http()>
<cfset httpRequest.setUrl(oAuthRequest.getUrl())>
<cfset httpRequest.setMethod(oAuthRequest.getMethod())>
<cfset httpRequest.addParam(type="header", name="Authorization", value=oAuthRequest.toHeader())>
<cfset httpRequest.addParam(type="header", name="Accept", value="application/json") />
<cfset httpRequest.setCharset("utf-8")>
<cfset httpResult = httpRequest.send().getPrefix()>
<cfdump var="#httpResult.filecontent#">
Error Response:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse time="2016-12-01T06:12:00.999-08:00" xmlns="http://schema.intuit.com/finance/v3">
<Fault type="AUTHENTICATION">
<Error code="3200">
<Message>message=ApplicationAuthenticationFailed; errorCode=003200; statusCode=401</Message>
<Detail>SignatureBaseString: GET&https%3A%2F%2Fsandbox-quickbooks.api.intuit.com%2Fv3%2Fcompany%2F123145723805019%2Fquery&oauth_consumer_key%3DqyprdTVZH2CtDAXewG1YQKQYzUssYH%26oauth_nonce%3D420ADB0BF9EF309B785C531EEE8A7AAF%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1480601520%26oauth_token%3Dqyprd5g2WEiaxaVyI3MqeXqRvxvi26cXuauyMtFQaMZHdjVT%26oauth_version%3D1.0%26query%3Dselect%2520%252A%2520from%2520customer</Detail>
</Error>
</Fault>
</IntuitResponse>
Encode the query statement before passing it into the URL.
Use the below method to perform the encoding:
<cffunction name="encodePercent" returntype="string" access="public"
description="RFC 3986 encoding - keep [ALPHA, DIGIT, '-', '.', '_', '~'], %-encode the rest -> decoding '~', correctly encoding spaces('+') and '*'">
<cfargument name="sValue" required="true" type="string" hint="value to encode">
<cfargument name="sEncoding" required="false" type="string" default="UTF-8" hint="encoding">
<cfset var sResult = "">
<!--- using javacast to call the appropriate encode method --->
<cfif Len(arguments.sValue)>
<cfset sResult = CreateObject("java","java.net.URLEncoder").
encode(JavaCast("String",arguments.sValue), JavaCast("String",arguments.sEncoding))>
<cfset sResult = Replace(sResult,"+","%20","all")>
<cfset sResult = Replace(sResult,"*","%2A","all")>
<cfset sResult = Replace(sResult,"%7E","~","all")>
</cfif>
<cfreturn sResult>
</cffunction>
You can keep the default value of the "sEncoding" argument as is.

Coldfusion 11 - Global variables - Application.cfc or Application.cfm

I'm working on an application done in Coldfusion 9. I have to migrate it in CF11 and I would like to improve the code. The current application in CF9 is done like this:
Application.cfm:
<cfapplication name="MyApp"
clientManagement="yes"
clientStorage="registry"
setClientCookies="yes"
sessionManagement="yes"
sessionTimeout="#CreateTimeSpan(0,1,0,0)#"
applicationTimeout="#CreateTimeSpan(0,0,2,0)#"
/>
<cfset application.datasource = "MyApp"/>
<cfset application.name = "MyApp"/>
<cfset application.access = "App"/>
<cfset application.version = "1.1"/>
<cfset application.title = "My Application"/>
<cfset application.inc_path = "includes"/>
<cfset application.com_path = "components"/>
<cfset application.scripts_path = "scripts"/>
<cfset application.styles_path = "styles"/>
<cfset application.email = "firstname.lastnane#myapplication.com" />
<cfset application.YEAR = 2016/>
<cfif Not IsDefined("session.language_cd")>
<cfset session.language_cd = "ENG">
</cfif>
<cfset session.email_support_team = "support#myapplication.com" />
<cfinclude template="ui_lib.cfm">
Inside the file "ui_lib.cfm", there are a lot of variables defined and used in all other .cfm files:
<cfswitch expression="#session.ui_lng_cd#">
<cfcase value="FRA">
<cfset ui_lib_abbrev = "Abbréviation" />
<cfset ui_lib_acces = "Accès" />
<cfset ui_lib_active_sans_accent = "Actif" />
</cfcase>
<cfcase value="ENG">
<cfset ui_lib_abbrev = "Abbreviation" />
<cfset ui_lib_acces = "Access" />
<cfset ui_lib_active_sans_accent = "Active" />
</cfcase>
</cfswitch>
For example in menu.cfm:
<div id="menu">
<h5><cfoutput>#session.user#</cfoutput></h5>
<ul>
<li><cfoutput>#ui_lib_abbrev#</cfoutput></li>
<li><cfoutput>#ui_lib_acces#</cfoutput></li>
<li><cfoutput>#ui_lib_active_sans_accent#</cfoutput></li>
</ul>
</div>
I have tried to create an Application.cfc to replace application.cfm:
<cfcomponent displayname="MyApp">
<cfset This.name = "MyApp">
<cfset This.sessionManagement="yes">
<cfset This.clientManagement="no">
<cfset This.loginStorage="session">
<cfset This.sessionTimeout = CreateTimeSpan(0,0,0,1)>
<cfset This.applicationTimeout = CreateTimeSpan(0,0,2,0) >
<cfset This.setClientCookies="no">
<cfset This.domainCookies="yes">
<cfset This.scriptProtect = "All">
<cffunction name="onApplicationStart">
<cfscript>
Application.homePage = "/index.cfm";
Application.datasource = "MyApp";
Application.name = "MyApp";
Application.access = "App";
Application.version = "1.1";
Application.title = "My Application";
Application.inc_path = "includes";
Application.com_path = "components";
Application.scripts_path = "scripts";
Application.styles_path = "styles";
Application.email = "firstname.lastnane#myapplication.com"
Application.YEAR = 2016;
</cfscript>
<cfinclude template="ui_lib.cfm">
</cffunction>
<cffunction name="onSessionStart">
<cfif Not IsDefined("session.language_cd")>
<cfset session.language_cd = "ENG">
</cfif>
<cfif Not IsDefined("session.g_exercice")>
<cfset todayDate = Now()>
<cfset SESSION.g_exercice = #DateFormat(todayDate, "yyyy")#>
</cfif>
<cfif Not IsDefined("session.sec_first_pass")>
<cfset SESSION.sec_first_pass = 0>
</cfif>
<cfset session.email_support_team = "support#myapplication.com" />
</cffunction>
</cfcomponent>
I have created application.cfc and removed application.cfm and tried to run the application. It's ok, but I have Coldfusion errors with the variables defined in ui_lib.cfm. The server says that the variables are not defined. Could you please tell me why and how to solve the problem?
I would like to know if it's better to use a file Application.cfc with the same definitions or keep the current file Application.cfm ?
Thanks in advance for your help.
I've done some cfm to cfc conversions and the answer depends upon the usage. As has been mentioned, session based logic in the application scope won't work.
If there's a way to change the user's language which updates the session.ui_lng_cd value and therefore the language displayed to the user then the easiest answer is to set language variables in the OnRequestStart event. You'll have to change the scope of the variables to the request scope when set and used but hopefully that'll be easy enough with a global search and replace.
Additional notes:
It would also be possible to store those language variables in the session, by placing the code in the OnSessionStart event but generally it's a good idea to keep session storage minimal as if you start storing a lot in session on a busy site it can use up a lot of memory.
Another way to do this that would take more work but I think is more efficient if you have a lot of these would be to create a two level array in the application that stores the language strings and use the session language as the first level of key. This way very little memory is used on each request to old variables.
So in your application.cfc OnApplicationStart you'd have:
application.languageStrings = {};
application.languageStrings["ENG"] = {};
application.languageStrings["ENG"]["ui_lib_abbrev"] = "Abbreviation";
application.languageStrings["ENG"]["ui_lib_acces"] = "Access";
application.languageStrings["ENG"]["ui_lib_active_sans_accent"] = "Active";
application.languageStrings["FRA"] = {};
application.languageStrings["FRA"]["ui_lib_abbrev"] = "Abbréviatio";
application.languageStrings["FRA"]["ui_lib_acces"] = "Accès";
application.languageStrings["FRA"]["ui_lib_active_sans_accent"] = "Actif";
And to output the right string you'd use:
#application.languageStrings[session.language_cd]["ui_lib_active_sans_accent"]#
The variables defined in your UDF are places in the variables scope, but by placing the UDF inside onApplicationStart(), the include happens only the one time instead of every request. I think you've figured that out and have them defined again in the variables scope.
I feel the more appropriate solution would be to place them into the application scope so they're just defined the one time instead of them being redefined on every request.
application.ui = {
"ENG" = {
"abbrev" = "Abbreviation"
, "acces" = "Access"
, "active_sans_accent" = "Active"
}
, "FRA" = {
"abbrev" = "Abbréviation"
, "acces" = "Accès"
, "active_sans_accent" = "Actif"
}
};
Then just update any existing reference like so: #application.ui[session.ui_lng_cd].abbrev#.
If your need to manage translated context grows in the future, take a look at Resource Bundles.

Coldfusion: passing a struct as String through url

Is there a simple way to serialize a single-level structure as a string for use in a url?
for example:
?key1=val1&key2=val2
<cfscript>
// create simple struct
x = { a=1, b=2, c=3 };
WriteDump(x);
// serialize in JSON format and encode for URL transport
y = URLEncodedFormat( SerializeJSON(x));
WriteOutput( 'url: #SCRIPT_NAME#?#y#');
// now receive the URL variable and dump it
if ( StructKeyExists( url, 'z' )) {
writeOutput( '<h3>URL Data:</h3>' );
writeDump( DeserializeJSON( URLDecode( z)));
}
</cfscript>
How does this look?
<cfset tmpStruct = {"firstItem" = "one", "secondItem" = "two"} />
<cfset myUrl = "http://domain.com/file.cfm?" />
<cfloop list="#structKeyList(tmpStruct)#" index="i" >
<cfset myUrl = myUrl & i & "=" & tmpStruct[i] & "&" />
</cfloop>
<cfset myUrl = left(myUrl,len(myUrl)-1) />
<cfdump var="#myUrl#" />