I spent a considerable amount of time today in two different e-mail threads, both from individuals trying to compare ColdFusion development to .NET development. So that I won't have to wade through all of this again any time soon, and in the hope that this discussion proves useful to others, I have extracted the core messages from both threads, and compiled them into this post.
Before going into specifics, there is a more fundamental issue that must be laid to rest. You have been asked to compare ColdFusion to .NET so as to determine the path for future application development. And frankly, what you have been asked to do does not make a whole lot of sense, and demonstrates a remarkable lack of understanding as to what exactly ColdFusion is and what .NET is not.
.NET is a platform and framework on which to build applications, and not just web based applications. .NET is the underlying engine which powers all sorts of applications (server apps, client apps, web apps, and more), and applications written for .NET leverage the .NET APIs to deliver needed functionality.
If you want to build .NET powered web applications, then you will likely do so using ASP.NET. ASP.NET (which is similar to classic ASP only in name) applications can be written in many languages, but VB.NET and C# tend to be the most popular. ASP.NET applications are collections of pages and controls that, together, create a complete application. And ASP.NET tends to be used to build the presentation tier of web applications (although that is not always the case).
ASP.NET applications are compiled and executed by a virtual machine, and at execution time the original language used to write the code becomes irrelevant. The application just runs, leveraging the framework within which it is running.
Of course, you can't do much with ASP.NET without knowing something about the underlying .NET world. But exactly how much of the guts you'd need to be aware of depends on what it is you are building and how you'd want to go about building it. Obviously, the more an ASP.NET developer knows about .NET and all it is capable of, the more he'll be able to leverage the power afforded by that platform. But that does not in any way suggest that simpler applications cannot be built without paying much attention to the .NET framework itself. (And indeed, Visual Studio .NET hides much of the underlying complexity from those who'd rather not pay attention to it).
So, .NET provides the framework and architecture, and ASP.NET is used to build web applications that take advantage of that underlying framework and architecture.
Now let's look at J2EE (or Java EE), an alternate and competing platform, created by Sun and supported by a whole slew of vendors and products. J2EE is a platform and framework on which to build applications, and not just web based applications. J2EE is the underlying engine which powers all sorts of applications (server apps, client apps, web apps, and more), and applications written for J2EE leverage the Java APIs to deliver needed functionality.
If you want to build Java powered web applications, then you have a few choices. You might use JSP which provides a page based scripting interface to Java based web applications. Or you may use ColdFusion which runs on top of Java. Both JSP and ColdFusion tend to be used to build the presentation tier of web applications (although that is not always the case).
ColdFusion (and JSP) applications are compiled and executed by a virtual machine, and at execution time the original language used to write the code becomes irrelevant. The application just runs, leveraging the framework within which it is running.
Of course, you can't do much with JSP without knowing quite a bit about Java. By contrast, you can do quite a lot with ColdFusion without knowing anything at all about Java, but you can do much more armed with Java know-how. The extent of Java exposure required depends on what it is you are building and how you'd want to go about building it. Obviously, the more a ColdFusion (or JSP) developer knows about Java and all it is capable of, the more he'll be able to leverage the power afforded by that platform. But that does not in any way suggest that simpler applications cannot be built without paying much attention to the Java itself.
So, Java provides the framework and architecture, and ColdFusion can be used to build web applications that take advantage of that underlying framework and architecture.
Do you see a pattern here? Comparing ColdFusion to .NET is a bit like comparing one vendor's finished car to another vendor's engine. It's just not apples-to-apples.
If you want to compare ColdFusion to .NET you have two avenues you can follow. You can perform a top-down comparison, first comparing the platforms (J2EE and .NET), and then comparing the web application development experience using ColdFusion on top of J2EE to that of using ASP.NET (on top of .NET). Or you can perform a bottom-up comparison, first looking at the development experience of ColdFusion and ASP.NET, and then comparing underlying architecture and platforms.
But either way, you need to separate the engine discussion from the application development experience discussion. Only then can you make educated recommendations and take defensible positions.
Oh, and for an overview of ColdFusion and how it relates to Java, see this post.
Day 1 of MAX Greater China is coming to a close. Once again, this is an incredibly high quality event, both polished and professional, and fun as well.
The opening keynote (which, including sponsor presentation and MAX awards, run 3.5 hours!) featured Tom Hale presenting the Macromedia platform and vision, Michael Gough on design, Mark Anders introducing Flex Builder, Bill Perry providing an update on Flash on devices ... and a band to provide an entertainment break.
I presented two sessions today, one on Flash Forms and the other on Printing and Reporting. Attendance at my sessions was on the low side, but that is actually typical of Asian conferences where the audience tends to be far more interested in Flash video and animation than anything else. Lots of interest in Flex Builder, and great hallway chatter, too.
More to follow.
This tutorial assumes that you have already installed the following:
The ColdFusion Flex 2 Adapter comes with installation instructions that must be followed very carefully. (Most initial problems are the result of the Adapter not be installed or configured correctly).
The Application The application that you will be building is a simple data drill-down application which uses the sample data that is installed with ColdFusion MX 7.0.1. On startup, the application displays a drop down combo box containing a list of artists. Selecting any artist displays that artist's art, and clicking on art items displays an image.
Setup Create a folder for your new application under your web root. The default I am using in this tutorial has a folder named flex under the web root, and a folder for this application named ArtCatalog in the flex folder. (On a default installation on a Windows machine this will therefore be c:\cfusionmx7\wwwroot\flex\artcatalog).
The Backend The backend for this application is a simple ColdFusion Component named art.cfc which contains two methods. GetArtists() returns the artist list, and GetArt() accepts an artistid and returns that artist's art. The CFC itself is very simple:
<cfcomponent> <!--- Get artists ---> <cffunction name="GetArtists" access="remote" returntype="query" output="false"> <cfset var artists=""> <cfset var result=""> <cfquery datasource="cfcodeexplorer" name="artists"> SELECT RTrim(lastname) + ', ' + RTrim(firstname) AS artist,
artistid
FROM artists
ORDER BY lastname, firstname
</cfquery> <cfquery dbtype="query" name="results"> SELECT artist AS label, artistid AS data
FROM artists
ORDER BY label
</cfquery> <cfreturn results> </cffunction> <!--- Get art for specified artist ---> <cffunction name="GetArt" access="remote" returntype="query" output="false"> <cfargument name="artistid" type="numeric" required="yes"> <cfset var art=""> <cfset var result=""> <cfquery datasource="cfcodeexplorer" name="art"> SELECT artid, artname, description, issold,
largeimage, mediaid, price
FROM art
WHERE artistid=
<cfqueryparam value="#ARGUMENTS.artistid#"
cfsqltype="cf_sql_numeric"> ORDER BY artname
</cfquery> <cfquery dbtype="query" name="results"> SELECT artid, artname, description, issold,
'
http://localhost:8500/cfide/gettingstarted/tutorial/images/' + largeimage AS image,
mediaid, price
FROM art
ORDER BY artname
</cfquery> <cfreturn results> </cffunction> </cfcomponent>
Notice that both methods query for data, and then query that query. There are two reasons for this. One, there is a bug in the current adapter whereby database query column names may not be converted to lowercase properly, querying the query solves this problem. Two, some Flex controls (like <mx:ComboBox>) have specific column name requirements, and the second query in GetArtists() renames the columns to the naming convention needed by that control.
It is generally a good idea to thoroughly test CFCs using simple ColdFusion calls before using them in your Flex apps. The following file named arttest.cfm can be used to test that art.cfc is functioning properly:
<cfinvoke component="art"
method="GetArtists"
returnvariable="artists">
<ul>
<cfoutput query="artists">
<li><a href="#CGI.SCRIPT_NAME#?artistid=#data#">#label#</a></li>
</cfoutput>
</ul>
<cfif IsDefined("URL.artistid")>
<cfinvoke component="art"
method="GetArt"
artistid="#URL.artistid#"
returnvariable="art">
<hr />
<cfdump var="#art#">
</cfif>
Defining The Service
Flex 2 applications access ColdFusion Components via Flash Remoting using a service name. This name must be defined in an XML file, mapping a destination name to a source (the path to the CFC).
When you installed the ColdFusion Adapter you copied a file named coldfusionsamples.xml into the WEB-INF\flex folder. Open that file, and add the following destination definition. The source here specifies flex\artcatalog\art as the path to the CFC (the .cfc extension should not be included), if you are using a different path make the necessary changes to the source.
<destination id="ArtCatalog">
<channels>
<channel ref="my-cfamf"/>
</channels>
<properties>
<source>flex.artcatalog.art</source>
<lowercase-keys>true</lowercase-keys>
</properties>
</destination>
Once you have made the change and saved the xml file, you will need to restart ColdFusion.
Creating The Project
Here are the steps needed to create the new Flex Builder project:
- Open Flex Builder 2.
- Select File, New, Flex Project.
- Specify ArtCatalog as the project name.
- Specify the project location (you can use the same folder as where you created art.cfc).
- The default Main Application File and Output Folder are ok, so click Finish to create the project.
- Right click on the new project in the Navigator panel, and select Properties to open the project Properties dialog.
- Select Flex Compiler.
- In the Additional compiler arguments field enter: -services=C:\CFusionMX7\wwwroot\WEB-INF\flex\flex-services.xml (or modify the path to match your installation).
- Click OK.
Building The Application
Now you can start building the application. The first thing you need to do is tell Flex how to find your CFC. You do this using the <mx:RemoteObject> tag, as follows:
<!-- ColdFusion CFC (via AMF) -->
<mx:RemoteObject id="artSvc" destination="ArtCatalog" showBusyCursor="true" />
Now, whenever you refer to artSvc Flex will be able to connect to art.cfc using the previously created mapping.
Next you'll define the artist drop down combo box. Here is the code (make sure to place it between the <mx:Application> tags, after the <mx:RemoteObject> tag):
<!-- Main display -->
<mx:VBox width="100%" height="100%">
<!-- Select artist -->
<mx:FormItem label="Artist:">
<mx:ComboBox id="artistsCB" dataProvider="{artSvc.GetArtists.result}"
width="150" />
</mx:FormItem>
</mx:VBox>
Save the code and run the application (click on the run button, the one with the white arrow in a green circle). The application should run, but the combo-box will not be populated . This is actually the correct behavior, you never called the CFC method, so there were no results to populate it with.
You want the GetArtists() method to be invoked automatically on application startup. To do that, create a ActionScript function named InitApp() as seen here:
<mx:Script>
<![CDATA[
public function InitApp():Void
{
artSvc.GetArtists();
}
]]>
</mx:Script>
Next, modify the <mx:Application> tag. Go to the end of the tag and press space, you should see a popup of all available properties and methods. Select the property named creationComplete and specify InitApp() as the value. The opening tag should now look like:
Save the code and run it again. This time the combo box should be automatically populated because the
dataProvider points to
artSvc.GetArtists.result (the result returned by the call to
GetArtists in the
artSvc service).
Next you'll create the data grid to display artist's art. Here is the code, place it after the tag:
<!-- Results -->
<mx:HBox width="100%" height="100%">
<!-- Results grid -->
<mx:DataGrid height="100%" width="100%" id="artGrid"
dataProvider="{artSvc.GetArt.result}">
<mx:columns>
<mx:DataGridColumn headerText="Name" columnName="artname" />
<mx:DataGridColumn headerText="Description" columnName="description" />
<mx:DataGridColumn headerText="Sold" columnName="issold" />
<mx:DataGridColumn headerText="Price" columnName="price" />
</mx:columns>
</mx:DataGrid>
</mx:HBox>
This code creates a grid containing four columns. (The grid columns could have been omitted, but then all columns would have been displayed, and you'd also have lost the ability to fine-tune the appearance of specific columns as you will see shortly). The grid's
dataProvider points to the result of
artSvc.GetArt().
Which means that method must be invoked. Modify the <mx:ComboBox> and add the following property and value:
change="{artSvc.GetArt(artistsCB.selectedItem.data)}"
This way, any time the combo box changed,
GetArt() will be called.
GetArt() requires that an argument be passed to it, the id of the artist who's art you wish to obtain. This argument is passed to
GetArt() as
artistsCB.selectedItem.data (the data value for the currently selected item in
artistsCB).
Now save and run the application. You should be able to select any artist to populate the data grid with his or her art.
Now add the following code so as to display an image of the art when an art item is selected in the grid. Place it after the </mx:DataGrid> tag and before the closing <mx:HBox> tag:
<!-- Image panel -->
<mx:Panel title="{artGrid.selectedItem.artname}">
<mx:Image height="200" width="200" source="{artGrid.selectedItem.image}" />
</mx:Panel>
This code creates a panel, setting the title to the artname currently slected in the data grid, and populate the source on an <mx:Image> tag with the image URL as returned by GetArt().
Using Cell Renderers
The default display in the data grid is fine for simple text data, but there are two columns that don't look right here. The Sold column is displaying true or false, which is not very intuitive. And the Price column is not formatting the values as currency values. Both of these problems can easily be addressed using cell renderers. Basically, a cell renderer is code that Flex should use to render cells instead of any default rendering.
The Sold column could use a checkbox to display a check if sold and not if not. To do this, simply add the following property to the appropriate <mx:DataGridColumn> tag:
cellRenderer="mx.controls.CheckBox"
If you run the application now you'll see that a checkbox is displayed, and will automatically be checked if true and not if false.
To format the Price column you will use a custom cell renderer, a new component. To create a new component do the following:
- Right click on the ArtCatalog project in the Navigator panel.
- Select New, MXML Component.
- Specify ArtPrice as the File name, and select VBox as the Base component.
- Click Finish.
Flex Builder will create a new component (based on <mx:VBox>) for you to use. When a component is called as a cell renderer, an object named
dataObject is passed to it containing the row to be rendered.
Add the following code in between the <mx:VBox> tags:
<mx:CurrencyFormatter id="cf"/>
<mx:Label text="{cf.format(dataObject.price)}" />
<mx:CurrencyFormatter> creates a formatter that knows how to format values as currency values. The <mx:Label> tag simply uses that formatter to display
dataObject.price (the price column of the current row).
The last thing to do is to tell Flex to use this new cell renderer. Go back to ArtCatalog.mxml and modify the price <mx:DataGridColumn> so that it includes the following:
cellRenderer="ArtPrice"
That's it. Save the files, and run the application. You can now select an artist, display art (formatted using cell renderers), and click on any art item to see it's image (not all of the items have associated images).
Application Source Code This downloadable zip file contains the ColdFusion and Flex source code.
Summary This application demonstrates basic ColdFusion Flex 2 integration, passing data to and from ColdFusion, as well as basic bindings and cell renderers.
Watch for more complex and powerful examples coming soon.