Search This Blog

Showing posts with label coldfusion. Show all posts
Showing posts with label coldfusion. Show all posts

Wednesday, April 2, 2014

ColdFusion: Variables-scope behavior in Application.cfc

The existence of Application.cfc is a huge enhancement over Application.cfm. Whenever feasible, always use Application.cfc. It provides methods, such as onApplicationStart(), onRequestStart(), onSessionStart(), onCFCRequest(), and so on. Understanding how the Application.cfc works is a bit confusing, especially when you come from Application.cfm. In this blog, I'd like to focus on how variables-scope behaves on the requested page when onRequestStart() and onRequest() are implemented.

We all know that any variables-scope variables defined in Application.cfm are available on requested page. Now, how can we translate this behavior to Application.cfc? Here's the answer. Variables-scope variables should be defined in onRequest(). If we defined in onRequestStart(), it would work as well. However, the variables would not be available on request page until onRequest() is implemented. In other words, any variables-scope defined in Application.cfc live inside until onRequest() is implemented.

BONUS: When implementing Application.cfc's native methods, don't add output="false". Simply omit it, unless you know what you are doing.

  • Adding output="false" is equivalent to cfsilent, which suppresses contents generated by CF tags.
  • Adding output="true" is equivalent to cfoutput, which evaluates expression between pound signs; and outputs other contents.
  • Omitting the attribute outputs contents.

Reference: Defining the application and its event handlers in Application.cfc

Saturday, February 22, 2014

ColdFusion: Implement Authentication for Web Services Using SOAP Header

The following script demonstrates how to implement authentication in SOAP header using ColdFusion.
We could pass username and password in simple value, but in this example we wanted to deliver them in XML.

NOTE: This blog has been updated with new code. The original one was written two years ago. :)

WebService.cfc

<cfcomponent output="false" hint="An example of Web Service.">

  <cffunction name="echo" output="false" access="remote" returntype="string" hint="Accept text/string; and return it back to the caller.">
    <cfargument name="message" type="string" required="false" default="" />
    
    <cfset var response = "It is NOT a SOAP request." />
    <cfset var namespace = "http://localhost/test/soap/" />

    <!--- Check if it is a SOAP request and the request is legit --->
    <cfif isSOAPRequest() AND authenticateRequest()>
      <cfset response = "It is a SOAP request. Echoes: " & arguments.message />
    </cfif>

    <cfreturn response />
  </cffunction>

  <cffunction name="authenticateRequest" output="false" access="private" returntype="boolean" hint="Authenticate request.">
    <cfset var result = false />
    <cfset var namespace = "http://localhost/test/soap/" />

    <!--- Get authentication node and return it as an XML --->
    <cfset var auth_node = getSOAPRequestHeader(namespace, "authentication", true) />

    <!--- Parse the authentication node content, which is credential --->
    <cfset var cred_node = xmlParse(auth_node.xmlRoot.xmlText) />

    <!--- Get the data from the XML --->
    <cfset var username = cred_node.xmlRoot["username"].xmlText />
    <cfset var password = cred_node.xmlRoot["password"].xmlText />   

    <!--- Verify the username and password --->
    <cfif NOT compare("jsmith", username) AND NOT compare("abc123", password)>
      <cfset result = true />

    </cfif>

    <cfreturn result />
  </cffunction>

</cfcomponent>

client.cfm

<!--- Settings --->
<cfset end_point = "http://localhost/test/soap/WebService.cfc?WSDL" />
<cfset ws_args = {refreshwsdl=true} /> <!--- Force ColdFusion to refresh WSDL stub --->

<!--- Create Web service object --->
<cfset web_service = createObject("webService", end_point, ws_args) />

<!--- Construct XML document, which contains username and password --->
<cfxml variable="xml_doc">
  <credential>
    <username>jsmith</username>
    <password>abc123</password>
  </credential>
</cfxml>

<cfset namespace = "http://localhost/test/soap/" />

<!--- Add credential in the header --->
<cfset addSOAPRequestHeader(web_service, namespace, "authentication", toString(xml_doc)) />

<!--- Add SOAPAction:"" in the header --->
<!--- The header field value of empty string ("") means that the intent of the SOAP message is provided by the HTTP Request-URI. 
  No value means that there is no indication of the intent of the message. 
  Reference: http://www.w3.org/TR/2000/NOTE-SOAP-20000508/ --->
<cfset addSOAPRequestHeader(web_service, namespace, "SOAPAction", chr(34) & chr(34)) /> <!--- The value can be empty --->

<cfset message = "Hello, there!">
  
<!--- Invoke the service --->
<cfset response = web_service.advancedEcho(message) />

<!--- Get the response in SOAP --->
<cfdump var="#getSOAPResponse(web_service)#" />

ColdFusion: Half Baked SOAP Support in ColdFusion 9

I've been on and off working on SOAP using ColdFusion 9 (CF9) for a while. I found out that the support of SOAP was not fully implemented. For example, when a SOAP exception happens, CF9 throws SOAP fault in the form of regular ColdFusion exception. That's definitely not right! We should deliver the fault in SOAP format. Again, this broken support is happening on CF9. I didn't check on other CF versions.

To fix the situation, I wrote a process to intercept the CF exception, parse the SOAP fault, and deliver it in SOAP format. First, I utilize onError() in Application.cfc to intercept an exception. Second, there is a CFC to parse the fault that is in the exception.

NOTE: My code includes a user-defined function, arrayOfStructsSoft() from Nathan Dintenfass. Thanks, buddy!

Application.cfc

<cfcomponent output="false">
  <cfset this.name = "soap" />

  <!--- When error occurred, the SOAP throws a ColdFusion exception that contains text-based fault info.
    That's the reason we need to parse and return it as a SOAP XML.
    This method generates SOAP envelope that contains fault in the body. --->
  <cffunction name="onError" returntype="void">
    <cfargument name="exception" required="true" /> 
    <cfargument name="eventName" type="string" required="true" />

    <cfset var soap_envelope = "" />
    <cfset var soap_fault = createObject("component", "SoapFault").init(arguments.exception['detail']) />
    <cfset var fault_string = toString(soap_fault.getFaultNode("xml")) />

    <!--- Remove XML header --->
    <cfset fault_string = replaceNoCase(fault_string, '<?xml version="1.0" encoding="UTF-8"?>', '') />

    <!--- Replace <Fault /> with <soapenv:Fault /> to follow ColdFusion naming conventions --->
    <cfset fault_string = replaceNoCase(fault_string, '<Fault>', '<soapenv:Fault>') />
    <cfset fault_string = replaceNoCase(fault_string, '</Fault>', '</soapenv:Fault>') />

    <!--- Embed the fault to SOAP envelope --->
    <cfsavecontent variable="soap_envelope">
      <soapenv:Envelope 
        xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" <!--- SOAP 1.1 --->
        xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <soapenv:Body>
          <cfoutput>#fault_string#</cfoutput>
        </soapenv:Body>
      </soapenv:Envelope>
    </cfsavecontent>

    <!--- Output the result as a SOAP XML. 
      So, the caller can receive and digest an exception/fault in SOAP format instead of ColdFusion native format. --->
     <cfcontent type="text/xml; charset=utf-8" />
    <cfoutput>#xmlParse(soap_envelope)#</cfoutput> <!--- xmlParse() converts string to XML --->
  </cffunction>

</cfcomponent>

SoapFault.cfc

<cfcomponent output="false">

  <cfset variables.instance = {} />
  <cfset variables.instance["fault"] = {} />

  <cffunction name="init" output="false">
    <cfargument name="exception" type="string" required="false" default="" />

    <cfif len(arguments.exception)>
      <cfset variables.instance["fault"] = parseFault(arguments.exception) />
    </cfif>

    <cfreturn this />
  </cffunction>

  <cffunction name="parseFault" output="false" access="public" returntype="struct">
    <cfargument name="exception" type="string" required="true" /> <!--- Receive an exception string from ColdFusion that contains SOAP fault information --->

    <!--- REFERENCE: http://axis.apache.org/axis/java/apiDocs/org/apache/axis/AxisFault.html --->

    <!--- The order should be matched with the one that ColdFusion outputs --->
    <cfset var node_list = "faultCode,faultSubcode,faultString,faultActor,faultNode,faultDetail" />
    <cfset var node_pos1 = 0 />
    <cfset var node_pos2 = 0 />
    <cfset var node_name = "" />
    <cfset var node_array[1] = {element_name=node_name, element_position=node_pos1} />
    <cfset var fault_info_pos1 = 0 />
    <cfset var fault_info = "" />
    <cfset var fault_node = "" />
    <cfset var result = {} />
    <cfset var i = 1 />

    <cftry>
      <!--- Build array that contains the element name and its position --->
      <cfloop list="#node_list#" index="node_name">
        <!--- Get the start position of each element --->
        <cfset node_pos1 = findNoCase(node_name & ":", arguments.exception) />

        <!--- Build a list based on what it is found --->
        <cfif node_pos1>
          <!--- Build a struct and set it to array --->
          <cfset node_array[i] = {element_name=node_name, element_position=node_pos1} />
          <!--- Increment array index --->
          <cfset i = i + 1 />
        </cfif>
      </cfloop>

      <!--- Sort the structure --->
      <cfset node_array = arrayOfStructsSort(node_array, "element_position", "asc", "numeric") />

      <cfloop index="i" from="1" to="#arrayLen(node_array)#">
        
        <!--- Assume that all node in the list is found. In other words, no element_position is zero. --->
        <cfset node_pos1 = findNoCase(node_array[i].element_name, arguments.exception) />
        
        <!--- Assume that faultDetail is in the last list --->
        <cfif node_array[i].element_name NEQ "faultDetail">
          <!--- Get the end position and use the next element as a reference --->
          <cfset node_pos2 = findNoCase(node_array[i+1].element_name, arguments.exception, node_pos1) />
        
        <cfelse>
          <!--- For the last element, faultDetail, use </pre> as the reference
            The tag is found in cfcatch.detail --->
          <cfset node_pos2 = findNoCase("</pre>", arguments.exception, node_pos1) />

          <!--- If cannot find the tag, find "hostname:"
            "hostname:" is found in cfcatch.faultString --->
          <cfif NOT node_pos2>
            <cfset node_pos2 = findNoCase("hostname:", arguments.exception, node_pos1) />
          </cfif>
        </cfif>
        
        <!--- Get the whole string from "elementName:" to the next element --->        
        <cfset fault_node = mid(arguments.exception, node_pos1, node_pos2 - node_pos1) />

        <!--- Get position of the current element value --->
        <cfset fault_info_pos1 = find(":", fault_node) + 1 />

        <!--- Get the element value --->
        <cfset fault_info = trim( mid(fault_node, fault_info_pos1, len(fault_node) - fault_info_pos1 + 1) ) />

        <!--- Insert in to a struct --->
        <cfset result[node_array[i].element_name] = fault_info />

      </cfloop>

      <cfcatch type="any">
        <cfloop list="#node_list#" index="node_name">
          <cfif node_name EQ "faultString">
            <cfset result[node_name] = cfcatch.message />
            
          <cfelseif node_name EQ "faultDetail">
            <cfset result[node_name] = cfcatch.detail />

          <cfelse>
            <cfset result[node_name] = "" />

          </cfif>
        </cfloop>

      </cfcatch>

    </cftry>

    <cfreturn result />
  </cffunction>

  <cffunction name="getFaultNode" output="false" returntype="any">
    <cfargument name="return_type" type="string" required="false" default="struct" />

    <cfset var result = "" />
    <cfset var root = "" />

    <cfif arguments.return_type EQ "struct">
      <cfset result = duplicate(variables.instance["fault"]) />

    <cfelseif arguments.return_type EQ "xml">
      <cfset result = xmlNew() />

      <!--- Create a root element --->
      <cfset result.xmlRoot = xmlElemNew(result, "Fault") />
      <cfset root = result.xmlRoot />

      <!--- For each element, create and populate the element --->
      <cfloop collection="#variables.instance["fault"]#" item="element">
        <!--- According to http://schemas.xmlsoap.org/soap/envelope/, the element name should be all lower case --->
        <cfset arrayAppend(root.xmlChildren, xmlElemNew(result, lCase(element))) />
        <cfset root[element].xmlText = xmlFormat(variables.instance["fault"][element]) />
      </cfloop>

    </cfif>

    <cfreturn result />
  </cffunction>

  <cffunction name="getFaultCode" output="false" returntype="string">
    <cfreturn variables.instance["fault"]["faultCode"] />
  </cffunction>

  <cffunction name="getFaultString" output="false" returntype="string">
    <cfreturn variables.instance["fault"]["FaultString"] />
  </cffunction>

  <cffunction name="getFaultActor" output="false" returntype="string">
    <cfreturn variables.instance["fault"]["faultActor"] />
  </cffunction>

  <cffunction name="getFaultDetail" output="false" returntype="string">
    <cfreturn variables.instance["fault"]["faultDetail"] />
  </cffunction>

  <cfscript>
  /**
   * Sorts an array of structures based on a key in the structures.
   * 
   * @param aofS   Array of structures. (Required)
   * @param key    Key to sort by. (Required)
   * @param sortOrder    Order to sort by, asc or desc. (Optional)
   * @param sortType   Text, textnocase, or numeric. (Optional)
   * @param delim    Delimiter used for temporary data storage. Must not exist in data. Defaults to a period. (Optional)
   * @return Returns a sorted array. 
   * @author Nathan Dintenfass (nathan@changemedia.com) 
   * @version 1, April 4, 2013 
   */
  private function arrayOfStructsSort(aOfS,key){
      //by default we'll use an ascending sort
      var sortOrder = "asc";    
      //by default, we'll use a textnocase sort
      var sortType = "textnocase";
      //by default, use ascii character 30 as the delim
      var delim = ".";
      //make an array to hold the sort stuff
      var sortArray = arraynew(1);
      //make an array to return
      var returnArray = arraynew(1);
      //grab the number of elements in the array (used in the loops)
      var count = arrayLen(aOfS);
      //make a variable to use in the loop
      var ii = 1;
      //if there is a 3rd argument, set the sortOrder
      if(arraylen(arguments) GT 2)
        sortOrder = arguments[3];
      //if there is a 4th argument, set the sortType
      if(arraylen(arguments) GT 3)
        sortType = arguments[4];
      //if there is a 5th argument, set the delim
      if(arraylen(arguments) GT 4)
        delim = arguments[5];
      //loop over the array of structs, building the sortArray
      for(ii = 1; ii lte count; ii = ii + 1)
        sortArray[ii] = aOfS[ii][key] & delim & ii;
      //now sort the array
      arraySort(sortArray,sortType,sortOrder);
      //now build the return array
      for(ii = 1; ii lte count; ii = ii + 1)
        returnArray[ii] = aOfS[listLast(sortArray[ii],delim)];
      //return the array
      return returnArray;
  }
  </cfscript>

</cfcomponent>

Thursday, October 24, 2013

ColdFusion: Error Handling

Most of time when we write code, we assume everything works like it should. However in reality, anything could happen. ColdFusion provides a way for us to handle exceptions gracefully. All these tags and the function are very useful, especially when the application interacts with third-party systems.

  • <cftry>...</cftry>
    Wrap code that could potentially cause an exception with this tag.
  • <cfcatch>...</cfcatch>
    This tag is placed inside <cftry> block. If an exception occurs, the tag would catch it; and we could handle it, such as logging the message or giving users a better error message.
  • <cfthrow />
    This tag is placed inside <cftry> block. If something did not work as expected, we could throw a custom exception and let <cfcatch> handles it.
  • <cfrethrow />
    This tag is placed inside nested <cfcatch> block. Nested <cftry>/<cfcatch> block provides a granular way to handle exceptions. If inner <cfcatch> could not handle it, we use <cfrethrow /> to send the exception to its parent.
  • onError()
    This function is placed in Application.cfc. It catches any errors that are not caught by <cftry>/<cfcatch> block. So, whether you implement <cftry>/<cfcatch> block or not in your code, it would be wise that you implement this function.

For more information about how to use those tags and function, please refers to error handling in ColdFusion documentation.

ADDED:
I found the referring document above is not complete. It's missing <cffinally>...</cffinally>. The tag is used to wrap processes that needs to be run before exiting <cftry>...</cftry>. Keep in mind, it is always run whether there is an exception or not. Without <cffinally>...</cffinally>, any code after <cfcatch>...</cfcatch> would cause an exception.

Some tips for writing better code:

  • Implement onError() in Application.cfc
  • Wrap code with <cftry>/<cfcatch>
  • Use <cfthrow /> for creating custom exception
  • Use <cffinally>...</cffinally> for running addtional processes after cfcatch
  • If there is nesting cftry/cfcatch, we can utilize <cfrethrow />

Tuesday, June 4, 2013

ColdFusion: CFTIMER vs. getTickCount()

In the old days, to measure how long a block of ColdFusion code is executed, we would use getTickCount(). Get the tick before and after the code in question; and subtract them. Newer versions of ColdFusion provide an alternative way to do the specified job. Wrap the code with <cftimer>...</cftimer>.
There is a downside using the tag, you will need to Enable Request Debugging Output in CF Admin. I also found that the "type" attribute is required instead of optional as stated on the documentation. It does not give us an error, but it will not show any results.

<cftimer type="outline">

 <cfset i = 1 />
 <cfloop index="i" from="1" to="100">
  <cfoutput>#i#</cfoutput>
  <cfset i = i + 1 /> 
 </cfloop>

</cftimer>

NOTE: I knew that we could use i++ or incrementValue(i), but I just wanted to use i=i+1 for clarity. :)

Monday, June 3, 2013

ColdFusion: Logging Errors Using BugLogHQ

I came across a bug/error logger called BugLogHQ. It includes a control panel where user can browse the logs. Setting it up is pretty easy. Follow its documentation page on http://www.bugloghq.com/docs.cfm.

A couple tips. This /bugLog/config/buglog-config.xml.cfm where you define the data source name (DSN), database type, username, and password. For security purpose, Personally, I would not recommend that you set username and password on this config file. If you chose to ignore the username and password, you would need to remove username and password attributes in /components/lib/dao/dbDataProvider.cfc. Otherwise, you would get an error. Another issue that I had during installation where I have MS-SQL Server 2008 installed using Windows authentication, this blog is certainly helpful.

Besides BugLogHQ, there are two other ColdFusion-based loggers I found. They are:

Friday, May 31, 2013

ColdFusion: Working with JSON

JSON has been gaining popularity to represent data in JavaScript applications. Below is an example of JSON data with some array and a ColdFusion parse function to convert JSON data to ColdFusion structure.

<cfsavecontent variable="personnel_record">
{
 "firstname": "John",
 "lastname": "Smith",
 "age": 36,
 "address": {
  "number": "12345",
  "street": "Any Street",
  "city": "Any City",
  "state": "AA",
  "zip": "90876"
 },
 "children": [
  {
   "firstname": "Ian",
   "age": 7,
   "married": false
  },
  {
   "firstname": "Heather",
   "age": 6,
   "married": false
  }
 ]
}
</cfsavecontent>

<cfdump var="#deserializeJSON(personnel_record)#" />

Wednesday, May 29, 2013

ColdFusion: Reduce/Suppress Whitespaces

Without implementing proper technique, by default ColdFusion generates unnecessary whitespaces on result page. This will cause the page size bigger and consequently it will take more time to load the page. To suppress the whitespaces, we can enable whitespace management in CF Admin and/or do one of the following techniques:

<cfsilent>...</cfsilent>
 Absolutely no output. Not even <cfoutput> nor <cfdump>.
 Require closing tag </cfsilent>.
 
output="false"
 One of the attributes in <cfcomponent> and <cffunction>.
 It works like <cfsilent>.
 
<cfsetting enablecfoutputonly="true">
 Only output things that are wrapped with <cfoutput>. 
 It works with <cfdump>.
 The effect goes to <cfinclude> as well.
 Matching tag, <cfsetting enablecfoutputonly="false"> is highly recommended.
 Closing tag </cfsetting> is optional and does not have any effect.
 Multiple declarations behave like a counter. 

<cfprocessingdirective suppresswhitespace="true">...</cfprocessingdirective >
 It reduces whitespaces, but it is not as effective as <cfsilent> or <cfsetting>.
 <cfoutput> is not required.
 Require closing tag </cfprocessingdirective>.

<!--- BONUS --->
<cfsetting showdebugoutput="false">
 Disable debugging mode when Debugging Settings in CF Admin is enabled.

SEE ALSO:
ColdFusion Whitespace Options

Friday, September 21, 2012

ColdFusion: Taking Advantage of Java Classes

ColdFusion is built on top of Java; and it has plumbing to access Java classes. This is pretty cool. That means we can extend ColdFusion's capability.

Here is an example on how to utilize Java's Stack class. What we need to do is to create an object from Java class in question. Here, we created a Stack. As you can see, we can immediately call and utilize its methods.

<cfset objStack = CreateObject("java","java.util.Stack").init() />
<cfdump var="#objStack#" />

<cfdump var="#objStack.empty()#" />
<cfset objStack.push("a") />
<cfset objStack.push("b") />
<cfset objStack.push("c") />
<cfdump var="#objStack.empty()#" />

<cfdump var="#objStack.peek()#" />

<!--- The top element is always one --->
<cfdump var="#objStack.search('c')#" />

NOTE: Often, when we work with electronic payments, the third-party may require us to use certain algorithm for encryption. In this case, Java has more options to choose from than the ones already built in ColdFusion. So, take advantage of Java classes.

Reference:

Monday, September 10, 2012

ColdFusion: Scale Attribute in <cfprocparam>

Want to insert a numerical value that contains decimal using <cfprocparam>, but the decimal portion is not showed up in the database? Most likely, we forgot to specify scale attribute. scale attribute is used to specify number of decimal places. If not specified, the default value is 0.

<cfstoredproc procedure="spuInsertBoxLength" datasource="#myDataSource#">
    <cfprocparam cfsqltype="CF_SQL_FLOAT" scale="2" value="123.45" />
</cfstoredproc>
Reference:

Thursday, August 23, 2012

ColdFusion: Converting Records From Excel to Query

Have you ever needed to get data from Excel to ColdFusion to be manipulated? Before ColdFusion 9, reading records from Excel was cumbersome. <cfspreadsheet> makes the task handy. You can convert the records to spreadsheet object, query, CSV, or even HTML.

Here is an example on how to read an Excel spreadsheet and convert its rows to ColdFusion query.

<cfspreadsheet  
    action = "read" 
    src = "spreadsheet.xls" 
    sheet = "1"
    excludeHeaderRow = "true" 
    headerrow = "1" 
    query = "queryName"
    rows = "2-10" />
 
<cfdump var="#queryName#" />

Attribute rows is useful during development. Instead of reading all records in once, you can just output several records for testing/debugging. For more information on other attributes, please see the reference below.

Reference:

Friday, April 20, 2012

ColdFusion: Immediate If vs. Ternary Operator

ColdFusion 9 introduces a new operator called ternary operator. Unlike iif(), ternary operator looks cleaner and less confusing.
See the snippet below. Pay attention on the quotes.

<cfparam name="condition" default="true">

<cfset var_1 = "TRUE">
<cfset var_2 = "FALSE">

<cfoutput>
 <!--- Use de() and quote will not evaluate the variable --->
 immediate if: #iif( (condition), de('var_1'), de('var_2') )#
 <br />
 <!--- Use quote 'var_1' or de(var_1) will evaluate the variable --->
 immediate if: #iif( (condition), 'var_1', 'var_2' )#
 <br />

 <!--- Use quote 'var_1' will not evaluate the variable --->
 ternary operator: #( (condition) ? 'var_1' : 'var_2' )#
 <br />
 <--- No quote var_1 will evaluate the variable --->
 ternary operator: #( (condition) ? var_1 : var_2 )#
</cfoutput>

Thursday, April 19, 2012

ColdFusion: argumentCollection vs. attributeCollection

Passing arguments/attributes via collection is very handy. However, you might get an unexpected error. This error could be caused by using argumentCollection or attributeCollection incorrectly.
See the code below and read the comments. I hope that helps! :)

<!--- Define a function to accept string and return it back to the caller --->
<cffunction name="echo" returntype="string" output="false">
 <cfargument name="aString" type="string" required="false" default="" />
 
 <cfreturn toString(arguments.aString) /> 
</cffunction>

<!--- Create a structure to hold an argument that will be passed to echo() --->
<cfset args_echo = structNew() />
<cfset args_echo.aString = "Hello World!" />

<!--- Call echo() and pass the argument via argumentCollection --->
<!--- NOTE: Notice that the argument name is "argumentCollection", instead of attributeCollection.
 In other words, if it is a function/method then use argumentCollection. --->
<cfoutput>#echo(argumentCollection=args_echo)#</cfoutput>


<!--- Create a structure implicitly (require CF8 and up); and declare attribute name and its value --->
<cfset args = {var="#args_echo#", label="args"} />

<!--- Call <cfdump> and pass the attributes via attributeCollection --->
<!--- NOTE: Notice that the attribute name is "attributeCollection", instead of argumentCollection.
 In other words, if it is a tag then use attributeCollection. --->
<cfdump attributeCollection="#args#" />