ColdFusion 9.0 Resources |
Using .NET classesContents [Hide]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> Note: You cannot load two DLLs with same fully qualified
name. ColdFusion always uses the first DLL that it accesses until
the server is restarted. For example, if page1.cfm uses c:\dev\a.dll
and page2.cfm uses c:\dev2\a.dll, and both DLLs have the same fully
qualified name, the first DLL file to be loaded remains loaded,
and both CFML pages use it.
When you create objects and access class methods and fields, and convert data types between ColdFusion and .NET, be aware of the following considerations and limitations:
Instantiating objects and calling class constructorsWhen 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:
Note: ColdFusion does not create instances of objects
if you use only their static methods.
Calling methodsYou 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)> Getting and setting fieldsYou 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. Converting between .NET and ColdFusion data typesAccessing .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. Some conversion limitations exist, 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 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 techniquesColdFusion 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.
Using decimal numbersUse 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 conversionsColdFusion 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, make sure to generate the proxy for System.Decimal as value type. Converting data to System.Object typeWhen 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, 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.
Note: You do not have to use a JavaCast function
to convert ColdFusion string variables. They are automatically converted
to .NET System.String.
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 no corresponding java types exist. The following table lists the .NET primitive types and the corresponding class you must use.
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 conversionsColdFusion 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. Working with complex .NET data typesWhen you use complex .NET data such as Hashtable, ArrayList and DataTable, ColdFusion normally automatically converts the data to the corresponding ColdFusion data type: 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 not case sensitive. 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, 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 ColdFusionColdFusion 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>Third element in the list is true</cfoutput> </cfif> Using ADO.Net DataTable in ColdFusionColdFusion 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 parametersWhen 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 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 dataYou 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 could want to disable the conversion 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 objectsUse 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. Using .NET objects.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. Note: The System.IO.DriveInfo is not included in the
.NET 1.x framework. It is included in .NET 2.0 and later frameworks.
For information on determining the .NET framework, see Determining and changing the .NET version.
<!--- 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#"> |