You use .NET assembly classes the same way you use Java and other objects that you create using the cfobject tag or CreateObject function. In the simplest case, your application code only has to use the following format to include a local .NET class method:
<cfobject type = ".NET" name = "mathInstance" class = "mathClass" assembly = "C:/Net/Assemblies/math.dll"> <cfset myVar = mathInstance.multiply(1,2)>
Using CFScript and the CreateObject function, you can do the following:
<cfscript> mathInstance = CreateObject(".NET", "mathClass", "C:/Net/Assemblies/math.dll"); myVar = mathInstance.multiply(1,2); </cfscript>
When you create objects and access class methods and fields, and convert data types between ColdFusion and .NET, you must be aware of the considerations and limitations described in the following sections:
When you use the cfobject tag to create a .NET object, ColdFusion does not create an instance of the object. ColdFusion creates the object instance in either of the following cases:
<cfobject type=".NET" name="myObj" class="com.myCo.MyClass" assembly="c:\assemblies\myLib.dll"> <cfset myObj.init(10, 5)>
You call .NET methods in the same way that you use any other ColdFusion object methods. For example, if the MyClass class has a getName method that takes a numeric ID and returns a name, you would call the method as follows:
<cfset theID="2343"> <cfset userName=mObj.getName(theID)>
You can access and change public fields of any .NET class by calling the following methods:
Get_fieldName() Set_fieldName(value)
For example, if the .NET class has a public field named accountID, you can access and change its value by using the Get_accountID() and Set_accountID() methods, as follows:
<cfobject type=".NET" class="com.myCo.MyClass" assembly="c:\assemblies\myLib.dll" name="myObj"> <cfset theAccount=myObj.Get_accountID()> <cfset myObj.Set_accountID(theAccount + 1)>
You can access, but not modify final fields, so you can only call Get_fieldName
() for these fields.
Accessing .NET classes requires a Java proxy on the ColdFusion system and .NET code on the target system, so data must be converted among ColdFusion, Java, and .NET (to be exact, Microsoft Intermediate Language, or MSIL) data types. ColdFusion converts data types automatically. Usually, you do not have to take any special steps to ensure correct conversion. There are some conversion limitations, and in some cases you must explicitly specify a data type when you call a method in a .NET proxy object.
The following paragraphs describe some the data conversion issues and how to handle them. For a detailed specification of how ColdFusion converts among ColdFusion data, Java data types, and .NET data types, see cfobject: .NET object in the CFML Reference.
Data type conversion rules and techniques
ColdFusion converts data automatically among ColdFusion, Java, and CLR data types. The following table indicates how ColdFusion converts among .NET Common Language Runtime (CLR) primitive and standard data types, the Java data types used in the proxies to represent CLR data types, and ColdFusion data types in your CFML application.
.NET type |
Java type |
ColdFusion type |
---|---|---|
sbyte |
byte |
Integer |
byte |
short |
Integer |
short |
short |
Integer |
ushort |
int |
Integer |
int |
int |
Integer |
uint |
long |
Number |
char |
char |
Integer or string |
long |
long |
Number |
ulong |
float |
Number |
float |
float |
Number |
double |
double |
Number The returned number retains greater precision than is normally displayed in ColdFusion. Use the PrecisionEvaluate function to access and display the full precision of a returned double value. You can also pass a value with full double precision to a .NET method. |
bool |
boolean |
Boolean |
enum |
|
Not converted, but enumerator elements can be accessed directly by using the format |
array |
array |
Array |
string |
String |
String |
System.Collections.ArrayList |
java.util.ArrayList |
Array Note: ColdFusion converts from .NET type to ColdFusion type only, it does not convert ColdFusion Arrays to .NET ArrayLists. |
System.Collections.Hashtable |
java.util.Hashtable |
Structure Note: ColdFusion converts from .NET type to ColdFusion type only, it does not convert ColdFusion Structures to .NET Hashtables |
System.Data.DataTable |
|
Query Note: ColdFusion converts from .NET type to ColdFusion type only, it does not convert ColdFusion Queries to .NET DataTables |
System.DateTime |
java.util.Date |
Date/time |
decimal System.Decimal |
java.math.BigDecimal |
String representation of the decimal number. For details on using decimal numbers, see Using decimal numbers. |
System.Object |
|
If a .NET argument is of type System.Object, ColdFusion Strings are converted directly. Other types require using the JavaCast function. ColdFusion cannot convert System.object instances returned by .NET methods to ColdFusion types, but you can access them using the Object methods. For detailed information, see Converting data to System.Object type. |
You must use the JavaCast function to convert ColdFusion data into BigDecimal format before you pass the value to a .NET function, as in the following example:
<cfset netObj.netFunc(javacast("bigdecimal","439732984732048"))>
ColdFusion automatically converts returned decimal and System.Decimal values to ColdFusion string representations.
Ensuring decimal and date/time conversions
ColdFusion converts .NET decimal or System.Decimal types only if the proxy for System.Decimal is a value type proxy. Similarly, it converts .NET System.DateTime values to ColdFusion Date-time values only if the proxy for System.DateTime is a value type proxy. The ColdFusion server always uses value proxies when it generates these proxies. If you use the JNBProxyGUI.exe tool to generate the proxy, however, you must make sure to generate the proxy for System.Decimal as value type.
Converting data to System.Object type
When a .NET method specifies System.Object (as opposed to a specific Object subclass, such as System.Boolean) as the argument type, and you want to pass primitive values as arguments to that method, you must use the javacast function to identify the data conversion. Once ColdFusion knows the data type, it automatically converts to the appropriate .NET type. Here is the table that describes the conversion rule from ColdFusion type to .NET type.
.NET Type |
Type used in javacast |
bool / System.Boolean |
boolean |
bool[] / System.Boolean[] |
boolean[] |
char / System.Char |
char |
char[] / System.Char[] |
char[] |
double / System.Double |
double |
double[] / System.Double[] |
double[] |
float / System.Single |
float |
float[] / System.Single[] |
float[] |
int / System.Int32 |
int |
int[] / System.Int32[] |
int[] |
long / System.Int64 |
long |
long[] / System.Int64[] |
long[] |
sbyte / System.Sbyte |
byte |
sbyte []/ System.Sbyte[] |
byte [] |
short / System.Int16 |
short |
short[] / System.Int16[] |
short[] |
System.Decimal |
bigdecimal |
System.String |
String |
You must create special objects for .NET primitive unsigned data types, such as byte (unsigned byte), ushort (unsigned short), uint (unsigned int) and ulong (unsigned long), for which there are no corresponding java types. The following table lists the .NET primitive types and the corresponding class you must use.
.NET type |
Class used in cfobject/createObject |
byte / System.Byte |
System.BoxedByte |
ushort / System.UInt16 |
System.BoxedUShort |
uint / System.UInt32 |
System.BoxedUInt |
ulong / System.UInt64 |
System.BoxedULong |
You must use the createObject function or cfobject tag to create these special objects, in the same manner as you create other .NET classes, before you use them in your assignment statement. For example, the following line creates a ushort representation of the value 100:
<cfset boxedUShort = createObject(".NET". "System.BoxedUShort").init(100)>
The following example creates a System.Hashtable object and populates it with examples of all types of primitives.
<!--- create a .NET Hashtable ---> <cfset table = createObject(".NET", "System.Collections.Hashtable")> <!--- call HashTable.add(Object, Object) method for all primitives ---> <cfset table.add("shortVar", javacast("short", 10))> <cfset table.add("sbyteVar", javacast("byte", 20))> <cfset table.add("intVar", javacast("int", 123))> <cfset table.add("longVar", javacast("long", 1234))> <cfset table.add("floatVar", javacast("float", 123.4))> <cfset table.add("doubleVar", javacast("double", 123.4))> <cfset table.add("charVar", javacast("char", 'c'))> <cfset table.add("booleanVar", javacast("boolean", "yes"))> <cfset table.add("StringVar", "Hello World")> <cfset table.add("decimalVar", javacast("bigdecimal", 123234234.505))> <!--- call HashTable.add(Object, Object) for unsigned primitive types. ---> <cfset boxedByte = createObject(".NET", "System.BoxedByte").init(10)> <cfset table.add("byteVar", boxedByte)> <cfset boxedUShort = createObject(".NET", "System.BoxedUShort").init(100)> <cfset table.add("ushortVar", boxedUShort)> <cfset boxedUInt = createObject(".NET", "System.BoxedUInt").init(123)> <cfset table.add("uintVar", boxedUInt)> <cfset boxedULong = createObject(".NET", "System.BoxedULong").init(123123)> <cfset table.add("ulongVar", boxedULong)> <cfdump var="#DotNetToCFType(table)#">
Any other .NET objects can be passed as it is.
Handling ambiguous type conversions
ColdFusion cannot determine the correct data type conversion if a method has multiple signatures with the same number of parameters that differ only in the parameter data types. In this case, use the JavaCast method to convert the ColdFusion data to the Java type that corresponds to the .NET type.
For example, if a .NET class has methods myFunc(ulong) and myFunc(int), use the JavaCast method to convert your ColdFusion variable to the Java float or int data type, as the following line shows:
myFunc(JavaCast(int, MyVar));
Similarly, if a .NET class has methods myFunc(int) and myFunc(String), use the JavaCast method to convert your ColdFusion variable to the Java int or String data type, as shown in the following line:
myFunc(JavaCast(String, "123");
In some cases, the JavaCast function cannot eliminate ambiguity because a single Java type corresponds to multiple .NET types. In these cases, ColdFusion creates a proxy with only one method, which uses the .NET data type that corresponds directly to a Java type.
For example, if the .NET class has methods myFunc(ulong) and myFunc(float), the generated proxy has only one method. This method calls myFunc(float), because the Java float type used to handle ColdFusion floating point numbers corresponds directly to the .NET float type. In this case, you can never call the .NET myFunc(ulong) method.
When you use complex .NET data such as Hashtable, ArrayList and DataTable, ColdFusion normally automatically converts the data to the corresponding ColdFusion datatype: structure, array and query, respectively . When you work with this data you take specific actions to enable the proper access and conversion of the data, as follows:
Using Hashtable data in ColdFusion
.NET Hashtables are case sensitive, but most methods of ColdFusion structure access are case insensitive. Only associative array notation of the form structName
["keyName
"] is case sensitive. When .NET Hashtables are converted to CF structure, the entire data set is converted, even if the element keys differ only in case. Therefore, to get the values of the keys that differ only in case, you must use associative array notation.
The following example shows this issue. It creates a Hashtable object with three entries whose key values vary only in case. In the example, output using dot-delimited structure notation always returns the same value, corresponding to the all-uppercase key, but associative array notation returns the correct result.
<!--- Create a Hashtable and convert it to a ColdFusion structure. ---> <cfset table = createObject(".NET", "System.Collections.Hashtable")> <cfset table.add("Key", "Value1")> <cfset table.add("KEY", "Value2")> <cfset table.add("key", "Value3")> <cfset cftable = DotNetToCFType(table)> <cfdump var="#cftable#"> <h3>Using dot notation</h3> Key : <cfoutput>#cftable.Key#</cfoutput><br> KEY : <cfoutput>#cftable.KEY#</cfoutput><br> key : <cfoutput>#cftable.key#</cfoutput><br> <p> <h3>Using associative array notation</h3> Key : <cfoutput>#cftable["Key"]#</cfoutput><br> KEY : <cfoutput>#cftable["KEY"]#</cfoutput><br> key : <cfoutput>#cftable["key"]#</cfoutput><br>
Using .Net ArrayList in ColdFusion
ColdFusion converts System.Collections.ArrayList objects to ColdFusion arrays, and you can perform all standard ColdFusion array operations on them. The following example shows this usage:
.Net Code:
public ArrayList getList(){ ArrayList myAL = new ArrayList(); myAL.Add("Hello"); myAL.Add(1); myAL.add(true); Return AL; }
ColdFusion Code:
<cfset cflist = netObject.getList()> <cfloop array="#cflist#" index="item"> <cfoutput>#item#</cfoutput><br> </cfloop> <cfif cflist[3]> <cfoutput>3rd element in the list is true</cfoutput> </cfif>
Using ADO.Net DataTable in ColdFusion
ColdFusion converts System.Data.DataTable objects to ColdFusion query objects, and you can perform all standard ColdFusion query operations on them. The following example shows this usage:
.Net code:
public DataTable datasetMethod() { //conn string string connectionString = "..."; //connection using (SqlConnection connection = new SqlConnection(connectionString)) { SqlCommand cmd = new SqlCommand(@"SELECT * FROM [tblEmployees]", connection); connection.Open(); SqlDataReader reader = cmd.ExecuteReader(); DataTable dt = new DataTable(); dt.Load(reader); return dt; } }
ColdFusion code:
<cfset query1 = netObject.datasetMethod()> <cfoutput query="query1"> Query1.CurrentRow = #query1.CurrentRow#<br> </cfoutput>
Using ColdFusion complex types in .NET input parameters
When a .NET method returns an ArrayList, Hashtable or DataTable, ColdFusion automatically converts it to a ColdFusion array, structure or query, respectively. However ColdFusion does not automatically convert from ColdFusion data types to these .NET types. (ColdFusion does automatically convert ColdFusion arrays to .Net array types.) Therefore, you cannot use ColdFusion variables directly as input parameters to .NET object instance methods that require .NET System.Collection.ArrayList, System.Collection.Hashtable, or System.Data.DataTable types. Instead you must create instances of these .NET types and populate them with the required data before you pass them to the .NET method. For an example of creating and populating a System.Collection.Hashtable object, see the example at the end of the "Converting data to System.Object type" section.
Disabling automatic conversion of complex .NET data
You can disable automatic conversion of .NET System.Collections.Hashtable, System.Collections.ArrayList or System.Data.DataTable objects to the corresponding ColdFusion structure, array or query objects. You might want to do this under the following circumstances:
To disable automatic conversion, set the JVM coldfusion.dotnet.disableautoconversion system property to true. For example, in a ColdFusion stand-alone server, or if you use JRun as your J2EE server, include the following setting in the JVM.config file:
-Dcoldfusion.dotnet.disableautoconversion=true
Manually converting complex .NET objects
Use the DotNetToCFType function to convert a System.Collections.Hashtable, System.Collections.ArrayList or System.Data.DataTable object to a ColdFusion structure, array or query respectively when either of the following circumstances are true:
For an example of using the function, see DotNetToCFType in the CFML Reference.
.NET fields and return values with class types are available in ColdFusion as .NET objects. You can use the object's methods to access object data and make it available to ColdFusion using supported data types.
The following example gets information about a system's drives. It calls the System.IO.DriveInfo.GetDrives() method to get an array of System.IO.DriveInfo objects, one per drive. It then calls the object methods to get specific information about the drives, and displays the information. The example uses a cfdump tag to simplify the code.
<!--- Create a query for the drive information results. ---> <cfset result=QueryNew("name,type,isready,format,label,totalsize,freespace" ,"varchar,varchar,bit,varchar,varchar,double,double")> <!--- Create a .NET System.IO.DriveInfo object. ---> <cfobject type=".NET" name="sidiClass" class="System.IO.DriveInfo"> <!--- Get the drives. ---> <cfset drives=sidiClass.GetDrives()> <!--- Loop through drives. ---> <cfloop from="1" to="#ArrayLen(drives)#" index="i"> <!--- Add a row to the query.---> <cfset QueryAddRow(result)> <!--- Get the drive name, type, and ready flag. ---> <cfset QuerySetCell(result, "name", drives[i].Get_Name())> <cfset QuerySetCell(result, "type", drives[i].Get_DriveType().ToString())> <cfset QuerySetCell(result, "isready", drives[i].Get_IsReady())> <!--- Get extra details ONLY if the drive is ready. ---> <cfif drives[i].Get_IsReady()> <cfset QuerySetCell(result, "format", drives[i].Get_DriveFormat())> <cfset QuerySetCell(result, "label", drives[i].Get_VolumeLabel())> <cfset QuerySetCell(result, "totalsize", drives[i].Get_TotalSize())> <cfset QuerySetCell(result, "freespace", drives[i].Get_AvailableFreeSpace())> </cfif> </cfloop> <cfdump var="#result#">