|
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
Hot Story Crossing the .NET Divide: CFMX, Web Services, and .NET
ColdFusion Web service interoperability with .NET
By: Joe Rinehart
Aug. 4, 2005 10:00 AM
Like it or not, .NET is proving a powerful force in the software industry. As a ColdFusion developer, you'll probably need to interact with it at some point in time. One of the promises of .NET is that it can provide this interoperability through Web services. Although it's easy to send simple data to and from .NET Web services, a little bit of extra work on our end can make arrays, structures, and even queries work across the two platforms. Quick Review: ColdFusion Web Services Web services use XML to provide remote procedure calls, or services, in a platform- and language-agnostic environment. By using the XML document Web Services Definition Language (WSDL), they describe how they work in a common, agreed-on format. When they communicate, data is sent in another XML format called Simple Object Access Protocol (SOAP). Although WSDL and SOAP are both fairly complicated, creating and consuming Web services in ColdFusion couldn't be easier! To create a service, create a ColdFusion component (CFC) file in a Web-accessible directory. Give it at least one function (or method), being sure to specify its return type and that its access attribute is set to remote. If the method has arguments, you must also specify the data type of those arguments. The following code shows a very simple ColdFusion Web service that returns a simple string:
<cfcomponent>
<cffunction name="getString"
returntype="string"
access="remote">
<cfreturn "Hello, world!">
</cffunction>
</cfcomponent>
After creating your CFC, it will be available as a Web service at http://<servername>/<path>/<filename>?WSDL. For example, if the code from the previous example was in "sampleService.cfc" under the root on your local machine, it would be available as a Web service at http://localhost/sampleService.cfc?WSDL. Consuming a Web service from ColdFusion is just as simple. In fact, it only takes one line of code. The following code shows how to consume and then display the results of our CFC from the previous example. In this example, we use the CFInvoke tag to both instantiate and call a method of our sample Web service. We then output the result in a standard CFOutput block:
<cfinvoke
webservice="http://localhost/
sampleService.cfc?WSDL"
method="getString"
returnvariable="result">
<cfoutput>#result#</cfoutput>
Now that we've reviewed creating and consuming Web services in ColdFusion, let's move on to creating Web services that can be consumed by .NET clients. Providing Data to .NET Through Web Services Sending Simple Values to .NET Lucky for us, .NET understands all of the simple ColdFusion return types without a hitch. This means that any Web service method returning these types can be understood by .NET without any changes. Table 1 shows the .NET data types that the results of your ColdFusion Web services will be translated into. You'll notice that three of the most powerful ColdFusion data types aren't listed in Table 1: arrays, structures, and queries. These are three of the complex data types available in ColdFusion. It's when we use ColdFusion Web services to send complex data types to .NET that we begin to encounter trouble. Sending Simple Arrays to .NET As long as your array contains simple values, you're in the clear. A .NET developer can easily loop over your result in the .NET equivalent of a collection-based CFLoop to extract the data. The following example shows the VB.NET code to do this:
For Each i In CFArrayResult
Response.Write("i: " & i)
Next
We'll tackle complex arrays, such as arrays of structures, after we've first taken a look at how a structure can be sent to .NET Sending Structures to .NET To return a structure to .NET, you create a "definition" CFC that will represent the structure and its data. Each member of the structure needs a corresponding CFProperty tag in the definition CFC. Instead of returning a structure, you first create an instance of the CFC. Then, use CFSet tags to set its properties to their corresponding values in your structure. Last, you return the instance of the CFC instead of your structure. It's important to note that you need to change the returntype of your CFFunction tag from "structure" to the (package) name of the CFC you're returning. In Listing 1, we take a look at how to do this. It first shows our definition CFC (employee.cfc) that represents an "employee" structure. Then, we have a Web service (employeeService.cfc) that creates the structure, translates it into the employee CFC, and returns the CFC. When the definition CFC is returned to .NET, .NET sees it as a type named after the interface component. In other words, the employee CFC returned in Listing 1 would be seen as an "Employee" object having directly accessible properties named EmployeeId, Firstname, and Lastname. On the .NET side, if the result was stored in a variable called "myEmployee," the employee's first name would be accessible as "myEmployee.Firstname." This is exactly as it would be in a ColdFusion structure. Combining Arrays and Structures On the .NET side, we first store the result in an object named "employees." Then, we loop over the members of the employee object with each being an instance of an employee. Knowing that the individual employee's data is stored in directly accessible properties, we can then print it out using simple "dot-syntax." Queries: XML to the Rescue! First, let me give you some background. The .NET equivalent of a ColdFusion query is called a DataSet. It's part of ADO.NET, which is the portion of .NET that deals with databases. DataSets are XML representations of database schemas. They can hold multiple queries, maintain relationships between the queries, and perform a slew of automated database tasks. From a ColdFusion perspective, what's great about DataSets is that we can easily create XML that a .NET client can turn into a DataSet. Listing 3 shows an example of XML that can be used to create a .NET data set. You'll see that it's fairly simple. A root-level tag defines a "table" named books, with each "book" node describing a row in that table. Inside each book node, we describe each column. In this case, the columns are the "author" and "title" nodes. Using ColdFusion MX's XML support, we can easily turn a query into this type of XML and return it to .NET as a string. To help out, I've created a user-defined function (UDF) that transforms queries into exactly this format of XML. This UDF is part of a utility CFC I've created called QueryTool, available on www.CFCZone.org or my site at: www.clearsoftware.net/client/queryTool.cfm. Listing 4 shows an entire solution for creating a query, transforming it to XML using this UDF, returning the XML, and finally the VB.NET client code for creating a DataSet from the result. Compatibility and Performance In my own applications, I'm using a two-tier approach to provide data to both ColdFusion and .NET clients. The first tier consists of a CFC with no modifications for .NET compatibility. ColdFusion applications can then call this component and its Web services with no changes. The second tier is also a CFC, used solely to provide data to .NET. It does this by instantiating the first-tier CFC as a component, calling the appropriate method, and then performing any necessary .NET-specific translations on the result. This way, any performance drains such as translating queries to XML only impact .NET clients, and I maintain compatibility with existing ColdFusion clients. Consuming Data from .NET Web Services Because of these differences in architecture, consuming .NET Web services is more difficult than consuming native ColdFusion Web services. In this section, we'll take a look at how to consume the various types of data returned by .NET Web services. Consuming Simple Types Consuming .NET Arrays For ColdFusion, this means that any complex data type sent over a .NET Web service will not be automatically translated into its ColdFusion equivalent. Instead, it will be translated into a Java object. This Java object will have various properties and methods, just like a CFC or COM object. You can CFDump the resultant object at any time to get a list of its properties and methods. If any of you have ever returned a CFC from a Web service, this should look very familiar. Now that you know this, if you're calling a .NET Web service that you think returns an array, don't be surprised when your result is an object. Unlike ColdFusion arrays, .NET arrays are of a specific type, meaning that each element of the array is of the same type. Simple arrays can be arrays of strings, numbers, or even raw bytes. Elements in more complex arrays can contain any type of object. If you CFDump the result of a .NET Web service returning an array, the object you receive will contain a method called "Get<type>()." In this, "<type>" is replaced by the name of the type of array you're expecting, such as "GetString()." If you call this method, the result is the native ColdFusion array you'd expect from a ColdFusion-based Web service. For a more complex example, if you expected a .NET Web service to return an array of our employee structures/objects, you'd look for a method called "GetEmployee()." This is because you're looking for an array of the employee type. Consuming .NET Structures If we consume the .NET equivalent of our ColdFusion GetEmployee Web service, we'd see a Java object with methods named "GetFirstname," "GetLastname," and "GetEmployeeId." Calling these would then return the Firstname, Lastname, and EmployeeId values or "properties" of this object. If we stored our result in a variable named "employee" and wanted to print out the employee's first name, we could reference it as #employee.GetFirstname()#. Consuming .NET DataSets What makes DataSets interoperable is that .NET uses XML to represent them. When calling a .NET Web service that returns a DataSet, exploration of the result leads to the discovery of a getAny() method. This method returns an array of objects representing the schema and data contained in a DataSet. These objects, in turn, have methods that expose their underlying XML. With a little bit of work, we can use ColdFusion MX's native XML support to translate this XML into ColdFusion queries. Again, I've created a UDF for dealing with .NET DataSets. Listing 5 shows both the UDF and an example of its use. This UDF can be downloaded from my Web site: www.clearsoftware.net/client/convertDotNetDataset.cfm. Because DataSets can contain multiple queries, my implementation returns a structure. Each member of the structure is a query named after the table's name in the .NET DataSet. Conclusion Supplemental Code Reader Feedback: Page 1 of 1
Your Feedback
Latest Cloud Developer Stories
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week
Breaking Cloud Computing News
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||