Migrating from ColdFusion to ASP.NET

 

Joel Mueller
Microsoft Corporation

July 2003

Applies to:
    Microsoft® ASP.NET
    Microsoft Visual Basic® .NET

Summary: Learn how to migrate from ColdFusion to ASP.NET. A comparison of ColdFusion MX and ASP.NET as well as common task scenarios for each application development framework are included. (25 printed pages)

Contents

Introduction
Architecture Comparison
Comparing Common Tasks
Summary

Introduction

Any migration begins with a solid understanding of how the capabilities of the source system map to the capabilities of the target system. Is there any functionality missing in the target system that might require the purchase of third-party components? What new capabilities might the target system provide? In this paper, we compare the capabilities of Macromedia's ColdFusion MX and Microsoft® ASP.NET Web application development frameworks and then examine how some common tasks are performed in each environment. By understanding the similarities and differences in these platforms, ColdFusion developers can begin to transform their expertise in ColdFusion Markup Language (CFML) into an understanding of ASP.NET development.

Architecture Comparison

The most fundamental of all architectural differences between ColdFusion MX and ASP.NET is the underlying framework that each is based upon. ColdFusion MX is Java-based, running on top of Macromedia's JRun server. It also supports a number of other industry-standard J2EE application servers. At runtime, all CFML pages are parsed and converted into Java source code, then compiled into Java bytecode before being executed. After the initial compilation, the cached bytecode for a page is re-executed without the need for further parsing or compilation.

ASP.NET is based on Microsoft's .NET Framework. At runtime, all ASP.NET pages are parsed and converted into source code for a .NET-compatible language (usually Microsoft Visual Basic® .NET or C#) and then compiled into Microsoft Intermediate Language (MSIL), a processor-independent bytecode with many similarities to Java bytecode. This MSIL is then further just-in-time compiled into native machine code before being executed. After the initial compilation, the cached native machine code for a page is re-executed without the need for further parsing or compilation.

Although the low-level frameworks underlying each system cannot be ignored, the most striking differences between ColdFusion MX and ASP.NET that many Web developers will notice occur at a much higher level—in the development and page execution models. While the details vary, ColdFusion follows the same development and page execution model as that of classic ASP, PHP, JSP, and other similar Web-scripting languages. Specifically, code is embedded in HTML markup, and as a given page executes from top to bottom, the output of the code's execution takes the place of the embedded code in the resulting HTML document. This development model is easy to grasp, but it does have a number of drawbacks. Chief among these is the lack of separation between application logic and presentation markup. Mixing code and presentation makes the code harder to read, which increases the time and effort involved in maintenance, and creates significant challenges for non-programming graphic designers who need to modify a page. Over the years, ColdFusion has introduced several ways to mitigate this lack of separation, including custom tags, and others—but the fundamental model remains.

ASP.NET, however, makes a very distinct break from the traditional model of Web application development. Rather than being linear and page-oriented, ASP.NET code is strongly typed, object oriented and event based. Basically, ASP.NET development is a blending of traditional Web development and traditional fat-client GUI development. Page elements are represented on the server-side by objects, each with its own properties, methods and events. An example is a page that posts back to itself and inserts some information from a form into a database. In ColdFusion, you might write some code to check for the existence of a form variable corresponding to the name of the HTML submit button to see if the page is loading for the first time, or as the result of a form submission. Then you would read the various form variables, validate them, and perform a database insert. If one or more form variables failed validation, you would need to write more code to display an error message to the user and to preserve the values the user has already entered. In ASP.NET, you simply bind a function to the Click event of a Button server control. Within this function, some code will read the Text property of the various form fields, represented on the server-side with TextBox objects. By the time the button's Click event has fired, form field validation has already been performed by any validation controls on the page, which also take care of displaying any necessary error messages to the user. Each individual TextBox takes care of preserving its own contents in the event users need to edit one or more of their entries.

For more information about ASP.NET's page framework, please see Introducing Web Forms.

Feature Matrix

Table 1 presents a comparison of some of the prominent features in ColdFusion MX and ASP.NET.

Table 1. Comparing the Features of ColdFusion MX and ASP.NET

Feature ColdFusion MX ASP.NET
Coding Language Has two related coding languages: CFML and CFScript. Most developers use a mix of CFML and CFScript. Supports more than 25 languages, but the 2 that are most-commonly used are Visual Basic .NET and C#. Most developers pick one language but can consume components written in any of the other supported languages.
Compiled Application Logic Supported, dynamically compiled. Supported, in both dynamically-compiled and precompiled modes.
Full-Page Output Caching Supported, caches different versions of the page based on all URL parameters. Supported, caches different versions of the page based on one or more URL parameters, browser type, a custom function or any combination.
Partial-Page Output Caching No built-in support. Built-in support through use of User Controls. Data and other objects can be cached with sophisticated expiration rules using the Cache API.
Database Access Supports Type III and Type IV JDBC drivers, as well as ODBC via a JDBC-ODBC bridge. Supports OLE-DB and ODBC directly, as well as including native drivers for MS SQL Server and Oracle.
Database Output Formatted output using looping with the CFOUTPUT or CFLOOP tags. Templated databinding to server-side controls for ease of development, or manual looping if that is preferred.
External Components Supports CORBA objects, Java and EJB object, and JSP tag libraries, as well as special extension tags written in C++ or Java. COM is supported, but from most reports is rather unreliable in the current release. Very good support for native C libraries and COM objects, as well as assemblies written in any .NET-compliant language, including Managed C++. No built-in support for CORBA objects or Java classes.
XML/XSLT Basic XML DOM and XSLT transformation is supported in an intuitive fashion, but there is little to no access to advanced features such as XML namespaces, XSD validation, and XSLT parameters. Lightweight stream-oriented parsing of large XML documents (such as SAX) is not supported. Comprehensive and easy-to-use support is provided for XML DOM, XSLT, validation, and lightweight stream-oriented parsing of XML documents.
XML Web Services The current release supports publishing and consuming Web services with a beta version of Apache Axis. Publishing and consuming Web services are very easy, but there are some known compatibility issues that may be corrected by an update that uses Apache Axis 1.0. Another major limitation is that asynchronous calls to Web services, and the creation of Web services that can be called asynchronously are not supported. The current release provides extensive and flexible standards-compliant support and makes it extremely easy to both publish and consume Web services. Asynchronous calls to Web services, and the creation of Web services that can be called asynchronously are supported with ASP.NET.
Session State Cookie-based, in-memory single-server session state, or cookie-based persistent "client state" using a database back-end. Cookieless sessions are supported but can require moderate-to-extensive modification of existing code in order to take advantage of them. Cookie-based or cookieless session state, using a single-server in-memory store, a centralized state server, or a database back-end. In addition, the extensible architecture allows for custom session-state modules to replace the built-in options. Cookieless sessions require only a configuration change to enable.
Built-In Functionality ColdFusion MX has built-in functions to cover many common tasks that a Web-based application may need to perform. It can also access Java class libraries with some extra work. ASP.NET has direct access to the entirety of the .NET Framework class libraries, which encompass a vast amount of functionality. This functionality is comparable to Java, but far more than is natively exposed in ColdFusion.
Regular Expressions Supports a mostly-Perl-5-compatible regular expression syntax, but has only partial Unicode support. Supports Perl-5-compatible regular expressions, with additional features such as right-to-left matching, precompiled expressions, named groups, full Unicode support. Also allows the user to specify a function to be called during a regular expression replace operation.
Debugging Includes extensive tracing and environment information that can be included in the page or displayed in a separate page. DreamWeaver MX and HomeSite+ allow for interactive debugging of pages as they execute, although the initial setup for debugging in either IDE can be difficult. Includes extensive tracing and environment information that can be included in the page, or displayed in a separate page. Visual Studio .NET allows for easy interactive debugging of pages as they execute, in addition to debugging of client-side JavaScript and SQL Server stored procedures.
Error Handling Supports structured error handling, raising custom errors, and specifying custom error pages for different types of unrecoverable errors. Supports structured exception handling (with the addition of a "finally" block for code that executes regardless of whether or not an error occurs), raising custom exceptions, and specifying custom error pages for different types of unrecoverable errors.
Charting Includes support for generating a variety of basic charts in JPG, PNG, or Flash format. No built-in support, although third-party components are available.
Image Manipulation No built-in support, although third-party components are available. Includes extensive image creation and manipulation facilities.
Code Re-Use Custom tags, user-defined functions, ColdFusion Components, and included files. User Controls, Server Controls, custom classes, and included files.
Threading No support, aside from the fact that simultaneous page requests happen in separate threads. Fully supported. Not only do simultaneous page requests happen in separate threads, but also each page can (if needed) spawn its own threads to perform simultaneous or asynchronous work.
Full-Text Search Includes a stripped-down version of the Verity search engine and allows access to a full-featured Verity K2 server. Can use any full-text search features provided by a database vendor, and other search engines can be accessed through their respective COM or Java API's. Does not include a built-in search engine but can access MS Index Server for full-text searching of files. Can use any built-in full-text search features provided by a database vendor. The Verity K2 server can be accessed through its provided COM and .NET API's, and other search engines can be accessed through their respective COM or .NET API's.
Data Caching Allows for time-based caching of database query results. Other types of data can be explicitly stored in application or session variables, but expiration and concurrency locking must be handled manually. Includes an extensive cache API that allows nearly any type of data (including database query results) to be stored, with expiration based upon time, usage, or dependency upon a file or another cached item. Also allows for a user-defined function to be called when a given item is removed from the cache.
Internationalization Supports Unicode strings and various character encodings and includes a variety of functions for converting numbers, currency, and dates to a locale-specific format. Some functions are culture-aware, and others are not. No built-in support for dynamically localizing an application into a specific language or culture. Supports Unicode strings and various character encodings. Date, number, and currency functions are all culture-aware and alter their output depending on what the current culture is set to (rather than requiring different functions to be called). Support for using resource files to dynamically localize an application is included.
SMTP, HTTP, FTP, POP3 Supported, although CFMAIL is generally viewed as rather unreliable. SMTP support depends upon the Internet Information Services (IIS) SMTP Service. HTTP has very good support. FTP and POP3 are not supported in .NET, but free and commercial third-party components are available for this functionality.
Web Server Support Supports IIS, Sun ONE, Netscape IPlanet, and Apache. Supports IIS and Covalent's commercial version of Apache 2.0.
Operating System Support Supports Windows, Linux, Solaris, and HP-UX. Currently supports Microsoft Windows® 2000, Windows XP, and the forthcoming Windows Server 2003.

Custom Tags vs. User Controls

Two features that bear a strong resemblance to one another are ColdFusion's custom tags and ASP.NET's user controls. Although superficially similar, there are some important differences to be aware of. Like custom tags, user controls are implemented as separate files that are built much like the pages that host them (the files have a slightly different extension, ascx instead of aspx). And similar to ColdFusion's custom tags, user controls are placed into a page using "custom tags" in the HTML markup. User controls can send HTML output to the browser, but unlike custom tags, user controls are typically not used for anything other than sending output to the browser. Also unlike custom tags, user controls are full-fledged objects with their own properties and methods. In that sense, they are closer to ColdFusion Components than custom tags.

User controls can encapsulate other controls and respond to the encapsulated controls' events. This capability allows for the creation of self-contained units of functionality, such as a log-in control that contains two TextBox controls and a Button and handles the button's click event, validating the username and password entered by the user. In this way, user controls can participate in the entire page lifecycle. Their methods can be called at any time while the various parts of the page are running, rather than having one routine executed only when the tag is encountered during processing (as with ColdFusion's custom tags).

For more information about user controls, please see Web Forms User Controls.

ColdFusion Components vs. Classes

Newly introduced in ColdFusion MX, ColdFusion Components (CFCs) represent the first real step for ColdFusion towards the encapsulation, flexibility and maintenance benefits of a true object-oriented system. CFCs can have multiple instances running at one time on a single page, with each instance containing its own data and each able to have its methods called to manipulate this instance data. ColdFusion Components support a limited amount of access control on methods and a limited form of inheritance. CFCs are not, however, truly object-oriented. They lack constructors, interfaces, protected members, method overloading and other trappings of a true object-oriented system.

If you're suffering from object-oriented buzzword overload, don't worry. All you need to know to get started is that most CFCs can be translated to classes in whatever ASP.NET-compatible programming language you happen to be using. However, while you can get by in ASP.NET with very little object-oriented knowledge, object-oriented concepts truly are one of the most powerful and productive techniques you could spend your time studying. You can find an introduction to the main areas of object-oriented programming (from a Visual Basic point of view) in Object-Oriented Programming in Visual Basic.

User-Defined Functions vs. Class Methods

User-defined functions in ColdFusion are a means of creating your own custom functions. These functions are not attached to any particular object, but rather are pseudo-objects in their own right, which can be stored in a number (but not all) of ColdFusion's built-in variable scopes or called directly in the context in which they were created.

There is no direct equivalent of user-defined functions in .NET, as .NET is an object-oriented framework and global functions are always attached to any object. The closest equivalent would be static (in C#) or Shared (in Visual Basic) methods. These methods are attached to a class, as all methods are, but they are attached globally to the class itself rather than to any instance of the class. For this reason, static/Shared methods can be called with ClassName.MethodName(), rather than needing to create an instance of the class and calling the method on that instance. These methods can be useful for utility functions that do not require any data other than what is passed to them when they are called.

XML Web Services

Both ColdFusion MX and ASP.NET provide support for XML Web Services, and both frameworks go to great lengths to make the creation and consumption of Web services an easy task. ColdFusion does so through an extension to ColdFusion Components that allows one or more methods of a CFC to be published as a Web service. When publishing a Web service, ColdFusion takes care of reading the CFC metadata and automatically generating a Web Services Description Language (WSDL) file that programmatically describes the service to consumers. When consuming a Web service, ColdFusion will read the service's WSDL file, and provide relatively transparent access to the methods described therein.

Similarly, you create a Web service in ASP.NET by making a file with the extension "asmx," and using attributes to mark which methods in the file should be exposed as Web service methods. The ASP.NET Framework takes care of generating a WSDL file from the Web service metadata. When consuming a Web service, the .NET Framework will take care of reading the service's WSDL file and automatically generating proxy classes that allow you to treat the remote services as if they were local objects. If additional control is needed, the proxy classes can be modified or even written by hand, if necessary.

As of this writing, ColdFusion's Web service implementation is based upon a beta version of Apache Axis, an open-source Web services framework. This beta version has some known incompatibilities with other frameworks, which can make interoperation with disparate sources (a fundamental tenet of XML Web Services) problematic. A forthcoming update to ColdFusion MX should upgrade its Axis support to version 1.0 and improve interoperability, but even then some issues will remain. ColdFusion does such a good job of hiding the underlying Simple Object Access Protocol (SOAP) implementation, that it can actually hinder interoperability. For example, ColdFusion provides no means of reading or writing to SOAP headers during a request, so a Web service that takes full advantage of the SOAP specification by requiring that authentication information be sent in a SOAP header, or requiring that the body be encrypted, simply will not work with ColdFusion. In addition, there is no indication when (or, indeed, if) ColdFusion will support emerging Web service standards, such as those covered in the recently-released Web Services Enhancements for Microsoft .NET, which includes support for the WS-Security, WS-Routing, WS-Attachments and DIME specifications.

Another significant limitation to the ColdFusion Web services implementation is the lack of support for asynchronous Web service calls. The ability to call Web services asynchronously allows application developers to make a Web service call and perform additional work (i.e. not "block") while waiting for the Web service to return. The capability to call Web Services asynchronously from an application, and the capability to create Web services that can be called asynchronously is critical to many application development scenarios. ASP.NET supports both.

Rich Controls

ASP.NET includes a large number of pre-built Server Controls that vastly simplify working with form-based Web applications. Some of these controls have analogs in ColdFusion's cfform and related tags, but the ASP.NET controls are for the most part significantly more powerful and flexible. ColdFusion includes cfform, cfinput, cftextinput and cfselect (which handle basic form elements and validation), as well as cfgrid, cftree and cfslider (providing a grid with inline editing, a tree control and a slider control, respectively; all three of which are implemented as client-side Java applets).

By way of contrast, ASP.NET's built-in controls do not require client-side applets and work regardless of the client's capabilities (up to a point—some controls won't get very far without basic client-side JavaScript support). If the browser is a modern version of Internet Explorer, the controls will emit code to allow rich interaction by using dynamic HTML. If not, the controls will fall back on traditional HTML with server round-trips for interactivity. Either way, the basic behavior and server-side code remains the same. In addition to basic form elements, ASP.NET includes an extensive array of form validation controls that you can use to specify required fields, a particular data type, or a range of values. They can even require that the input match a given regular expression or can apply a custom validation function that performs more complex validation logic. These validation controls perform their validation both on the client (for faster response and fewer roundtrips) and on the server (for unsupported browsers or those that have scripting turned off).

Another rich control included in ASP.NET is the DataGrid. At its most basic, this control is generally used for displaying the results of a database query in an HTML table in the browser. However, with only a few extra lines of code, the DataGrid supports paging through large sets of data, sorting on columns, and inline editing of data, all without requiring any client-side downloads or special capabilities. Other built-in controls include the Calendar, which draws a dynamic calendar on the page, allowing the user to intuitively select a date; the AdRotator, which allows for easy and configurable displaying of ad banners on a page; and the Xml control, which provides an easy and intuitive way of performing XSLT transformations of XML Data to produce content.

Numerous free and commercial third-party server controls are becoming available for ASP.NET. Microsoft also supplies a set of additional controls that include TreeView, TabStrip, and Toolbar controls.

Comparing Common Tasks

The following sections provide comparisons of how to accomplish some common programming tasks in ColdFusion, and in one of the most-common ASP.NET languages, Visual Basic .NET.

Output

The typical way of outputting data in ColdFusion is with the c Extensible Stylesheet Language Transformations ut tag, or with WriteOutput() in CFScript. The closest analogue to this in ASP.NET is the Response.Write() method, or the <%= %> construct, which is simply shorthand for Response.Write(). Table 2 shows basic syntax for writing a value to the page.

Table 2. Basic Output

CFML Visual Basic .NET
<cfoutput>
The current date is: #Now()#
</cfoutput>
The current date is: 
<% Response.Write(DateTime.Now) %>
Or:
The current date is: 
<%= DateTime.Now %>

However, these methods for sending output to the browser exist primarily for backwards compatibility with classic ASP. ASP.NET's new control-based, event-oriented model allows for data to be output to the browser by simply setting properties on server controls. This technique allows for clean separation of layout and code and can make maintenance easier, requiring significantly less code in complex situations.

<script language="VB" runat="server">
Sub Page_Load(sender As Object, e As EventArgs)
  TheDate.Text = DateTime.Now
End Sub
</script>
The current date is: <asp:Label id="TheDate" runat="server"/>

This example declares a server-side Label control, and during the page's Load event, sets the Text property of the label to the current date and time. The HTML output of this code is identical to the other two versions, except that the Label control renders itself as a span tag containing whatever was set as the label's text.

Comments

ColdFusion allows you to insert server-side comments in a page, and anything within those comment indicators will be removed from the page and not sent to the browser. Server-side code in a comment block will not be executed. In addition, CFScript Extensible Stylesheet Language Transformations (XSLT) has its own comment syntax: a double-slash (//) at the beginning of a line will comment out the entire line.

ASP.NET has equivalents for both types of comments. A comment block in an aspx page will not be sent to the browser, and any server code contained in that block will not be executed. In addition, each .NET language has its own comment syntax for writing comments within a block of code. In Visual Basic, a single apostrophe (') at the beginning of a line will comment out the entire line. Table 3 shows server-side comments in each environment.

Table 3. Server-Side Comments

CFML ASP.NET
<!---
  This is a comment.
--->
<%--
  This is a comment.
--%>

Conditional Processing

CFIF/CFELSE

The two main groups of conditional processing tags in ColdFusion are cfif/cfelseif/cfelse and cfswitch/cfcase/cfdefaultcase. Visual Basic .NET has equivalent constructs with fairly similar syntax. Table 4 provides a comparison of equivalent conditional logic in CFML and Visual Basic .NET.

Table 4. Basic Conditional Logic

CFML Visual Basic .NET
<cfif x GT y OR x EQ z>
<!--- do something --->
<cfelseif x LT m AND x GT r>
<!--- do something else --->
<cfelse>
<!--- do a third thing --->
</cfif>
If x > y OrElse x = z Then
  ' do something
ElseIf x < m AndAlso x > r Then
  ' do something else
Else
  ' do a third thing
End If

It should be noted here that Visual Basic .NET has And and Or operators as does ColdFusion. However, they behave slightly differently than the ColdFusion versions. The And and Or operators in ColdFusion are short-circuiting operators. If the statement on the left side of the operator fails its test, the statement on the right side of the operator will not be executed. This allows statements such as the following example, which first checks for the existence of a variable called "x", and then checks the value of one of its properties. If the existence test fails, the second part of the statement will not be executed.

<cfif IsDefined("x") AND x.SomeProperty EQ true>

In Visual Basic .NET, the And and Or operators are not short-circuited; all statements will be executed regardless of the result of the earlier statements. This behavior can be a critical difference. Consider the following code that is seemingly equivalent to the last statement:

If Not x Is Nothing And x.SomeProperty = True

Although this code seems identical, it will actually generate an error in the case where x is Nothing. Because all statements are evaluated, Visual Basic will try to read the property of a non-existent object. In order to get short-circuiting behavior equivalent to that in ColdFusion, you must use the AndAlso and OrElse operators, which are newly introduced in Visual Basic. NET.

Visual Basic .NET will attempt to coerce integer and other values into Boolean values if they are used directly in an If statement (0 becomes false; anything else becomes true), just as ColdFusion does. However, if Visual Basic's Option Strict is enabled, If statements will accept only true Booleans. Shortcuts such as "If y Then" become impossible and must be replaced by "If y > 0 Then" because the greater-than operator returns an actual True or False value. In general, the restrictions imposed by Option Strict are viewed as a good thing, because they force programmers to be more explicit about their intentions, reducing the chance of causing a difficult-to-diagnose bug.

CFSWITCH

When you test a single expression for multiple values, the cfswitch statement can be both easier to read and better performing than multiple cfif/cfelseif statements. The same holds true in Visual Basic. NET, through the Select Case statement. Table 5 shows a comparison of ColdFusion's cfswitch statement and Visual Basic's Select Case statement.

Table 5. A Comparison of cfswitch and Select Case

CFML Visual Basic. NET
<cfset num = 4>
<cfset description = "">
<cfswitch expression="#num#">
   <cfcase value="1,2,3,4,5">
      <cfset description = "Between
        1 and 5">
   </cfcase>
   <cfcase value="6,7,8">
      <cfset description = "Between
        6 and 8">
   </cfcase>
   <cfcase value="9,10">
      <cfset description = "Greater
        than 8">
   </cfcase>
   <cfdefaultcase>
      <cfset description = "Not
        between 1 and 10">
   </cfcase>
</cfswitch>
Dim num As Integer = 4

Dim description As String = ""

Select Case num

Case 1 To 5

description = "Between 1 and

5"

Case 6, 7, 8

description = "Between 6 and

8"

Case 9 To 10

description = "Greater than

8"

Case Else

description = "Not between 1

and 10"

End Select

Looping

With the exception of using cfoutput to write a query result set to the browser, virtually all looping in CFML is accomplished with the cfloop tag. Visual Basic (along with most other .NET languages) has different language elements for different types of looping rather than a single language element with different attributes. Table 6 shows a basic index loop in each language.

Table 6. Index Loop

CFML Visual Basic. NET
<cfset sum = 0>
<cfloop index="counter" from="1" 
  to="100" step="5">
   <cfset sum = sum + counter>
</cfloop>
Dim sum As Integer = 0
Dim counter As Integer
For counter = 1 To 100 Step 5
   sum += counter
Next

In Visual Basic, this type of loop is known as a For…Next loop. In this example, the += operator is used as shorthand for "sum = sum + counter." A cfloop can be broken out of with the cfbreak statement. A For…Next loop can be broken out of with the Exit For statement.

Conditional Loop

A conditional loop iterates over a set of instructions as long as a condition evaluates to true. Table 7 shows an example of a basic conditional loop in each language.

Table 7. Conditional Loop

CFML Visual Basic. NET
<cfset counter = 0>

<cfloop condition="counter LESS THAN OR EQUAL TO 10">

<cfset counter = counter + 1>

</cfloop>

Dim counter As Integer = 0

Do While counter <= 10

counter += 1

Loop

In Visual Basic, this type of loop is known as a Do. . .Loop statement, or a while loop. The Do. . .Loop statement, however, has some additional capabilities not directly available in a cfloop conditional loop. It includes the ability to loop until a condition is true, rather than while a condition is true:

Do Until counter > 10
   counter += 1
Loop

The code inside either a conditional cfloop or a Do…Loop statement will not be executed at all if the loop condition is not met when the statement is first processed. However, unlike cfloop, the Do. . .Loop statement can be reversed, so that the code inside the loop is always executed at least once, and then more times if conditions warrant.

Do
   counter += 1
Loop While counter < 11

This construct is not as commonly used as a normal loop but can be useful in certain situations.

Collection Loop

ColdFusion can use cfloop to iterate over every item in a collection or structure. This functionality is covered natively by each language supported by ASP.NET. In Visual Basic .NET, the equivalent is the For Each. . .Next statement. Table 8 shows an example of looping over a collection in each language.

Table 8. Looping Over a Collection

CFML Visual Basic. NET
<cfloop collection="#myStruct#" 
  item="key">
   <cfoutput>
   #key# = #myStruct[key]#
   </cfoutput>
</cfloop>
For Each key In myHashTable.Keys
   Response.Write(key + " = " + 
     myHashTable[key])
Next

Query loop

Looping over a query with cfloop has no direct analogue in any ASP.NET language. The reason is that database query results are not treated as a special type of object. Typically database queries are returned from ADO.NET as DataSet or IDataReader objects. A DataSet can be traversed with either a For. . .Next loop or a For Each. . .Next loop, while an IDataReader can be traversed with a Do While. . .Next loop. However, in many cases it is not necessary to manually loop over a set of query results at all. Both the DataSet and the IDataReader can be bound directly to an ASP.NET server control, such as the DataGrid, which will take care of extracting data from the result set and formatting it for you.

Setting and Retrieving Session Variables

Session variables in ASP.NET are at their most basic level very similar to ColdFusion's session variables. They are cookie-based, expire after a configurable span of inactivity, and can store nearly any type of object. There are, however, some important differences that should be noted. Perhaps most significantly for ColdFusion developers, reads and writes to ASP.NET session variables seldom need to be locked. Unless there's a strong possibility that a page that writes to a session variable and a page that reads from the same session variable could be called simultaneously from the same client, there is no need to slow your application by locking every single session variable access. Other differences include cookieless sessions and out-of-process or database-based session storage, all available through simple configuration file changes.

The last important difference is that when a value is retrieved from the ASP.NET session object, it is returned as the generic System.Object type, which can hold any type of data. This value must be converted back to its original underlying type before it can be used. Table 9 shows some examples of session variable usage.

Table 9. Session Variable Usage

CFML Visual Basic. NET
<cfset Session.Today = Now()>
<cfset today = Session.Today>
<cfoutput>#today#</cfoutput>
Session["Today"] = DateTime.Now

Dim today As Date

today = CDate(Session["Today"])

Response.Write(today)

Error Handling

The .NET framework includes support for structured exception handling very similar to ColdFusion's cftry/cfcatch/cfthrow tags, with the notable addition of a Finally block, which allows for code to be executed regardless of whether an error occurred in the Try block. This can be very useful for performing clean-up operations. Table 10 shows a comparison of error handling in each language.

Table 10. Structured Exception Handling

CFML Visual Basic. NET
<cftry>
   <!--- code that might cause an 
  error here --->
   <cfcatch type="exceptiontype">
      <!--- code to handle the 
        error --->
   </cfcatch>
   <!--- Optional: More cfcatch 
     blocks --->
</cftry>
Try

' code that might cause an error

here

Catch e As ExceptionType

' code to handle the error

' Optional: More Catch blocks here

Finally

' code that is always executed

End Try

It is worth noting that a Try block can have either one or more Catch blocks, or a Finally block, or both. In other words, in situations in which you know that there is no way to correct for an error, but you still need to clean up some objects regardless of whether an error occurs or not, you can use a Try. . .Finally block with no Catch statement.

Arrays

ColdFusion arrays support any data type, dynamically resize themselves, and are multi-dimensional only in the sense that they support nested arrays-of-arrays. Arrays in the .NET framework (and by extension, Visual Basic. NET and other languages) are more restrictive in some areas, less in others, and perform better in nearly all areas.

Visual Basic. NET arrays must be declared as holding a specific type of data when they are created. If the type specified is Object (the generic type underlying every object type in .NET), then the array can hold any type of data, but values must be converted to their original type when they are retrieved from the array. This restriction is generally viewed as a good thing, as the compiler is able to make some significant performance optimizations in cases in which it knows exactly what type of data an array can hold. In addition, it prevents the programmer from accidentally adding a string to an array of dates, potentially causing a hard-to-find error later when the array is read.

Visual Basic. NET arrays can be either nested arrays-of-arrays (or jagged arrays), as in ColdFusion, or true multi-dimensional arrays. Arrays in Visual Basic. NET do not automatically resize themselves as in ColdFusion; you must explicitly resize the array with the ReDim Preserve statement. However, if a resizable array is needed, it is often advisable to use the System.Collections.ArrayList object, which does dynamically resize as needed and can give significantly better performance than ReDim Preserve.

One final difference to note is that unlike in ColdFusion, assigning an array to a new variable does not implicitly make a copy of that array. Rather, it makes a copy of the reference to the same array; changes to the new variable will affect the original array. In order to make a copy of an array, you can use the Clone() method attached to any array object, or the global Array.Copy() method.

For more detailed information about declaring and manipulating arrays in Visual Basic. NET, see the language reference.

Structures and Other Collections

The ColdFusion Structure object is quite extensively used in many ColdFusion applications. In fact, it forms the basis of most of the variable scopes in ColdFusion, such as Form, URL, Session, Request, CGI and so on. The equivalent in any ASP.NET language is the System.Collections.Hashtable object. The System.Collections namespace also contains many other more specialized collection objects that can be useful in various situations.

Regular Expressions

The .NET framework provides extensive support for regular expressions. The syntax supported is slightly different from that supported by ColdFusion, and .NET provides some additional capabilities not present in the current version of ColdFusion. Some of the capabilities include full Unicode support, pre-compiled expressions, and the ability to specify a custom function to be called during a regular expression replace operation. For more information about .NET's regular expression support, see .NET Framework Regular Expressions.

Sending Email

Built-in support for sending SMTP is included in ASP.NET, but has some external dependencies. Specifically, the IIS SMTP service must be installed because the built-in mail objects depend on the CDONTS objects included with the service. Table 11 shows the minimum code required to send an email in each language.

Table 11. Sending Email

CFML Visual Basic. NET
<cfmail to="foo@bar.com"
   from="bar@foo.com"
   subject="Test Message">
This is a test message.
</cfmail>
Dim myMail As MailMessage = New 
  MailMessage()
myMail.From = "foo@bar.com"
myMail.To = "bar@foo.com"
myMail.Subect = "Test Message"
myMail.Body = "This is a test message."
SmtpMail.Send(myMail)

Date/Time Manipulation and Formatting

ColdFusion date-time variables can range from the year 100 Common Era (CE) to the year 9999, with a minimum resolution of one second. ColdFusion includes an extensive set of functions that can operate on date-time variables to manipulate them and extract the various components (year, month, hour).

DateTime objects in .NET can range from the year 1 CE to the year 9999, with a minimum resolution of 100 nanoseconds (one "tick"). Functionality for manipulating DateTime objects and extracting the various components is attached directly to the DateTime objects themselves, as Table 12 shows.

Table 12. Date Manipulation

CFML Visual Basic. NET
<cfset today = Now()>
<cfset thisYear = Year(today)>
<cfset thisMonthName = 
  MonthAsString(Month(today))>
<cfset nextMonth = DateAdd("m", 1, 
  today)>
<cfset difference = DateDiff("d", 
  today, nextMonth)>
<cfset dateString = 
  DateFormat(today, "full")>
Dim today As DateTime = 
  DateTime.Now
Dim thisYear As Integer = 
  today.Year
Dim thisMonthName As String = 
  today.ToString("MMMM")
Dim nextMonth As DateTime = 
  today.AddMonths(1)
Dim difference As Long = 
  DateDiff("d", today, nextMonth)
Dim dateString As String = 
  today.ToString("F")

One important difference to note is that, the equivalent of the DateFormat() function is the ToString() method of the DateTime object. Passing in a format string tells the DateTime object how to format the resulting string. For information about what format strings can be used, refer to Date and Time Format Strings.

Setting and Retrieving Cookies

Cookie support is fairly standard across any Web scripting language, and ASP.NET is no exception. Table 13 shows an example of writing and then reading a cookie in each language.

Table 13. Setting and Retrieving Cookies

CFML Visual Basic. NET
<cfcookie name="LastVisit"
   value="#Now()#"
   expires = "#DateAdd('d', 10,
     Now())#">
..
<cfoutput>#Cookie.LastVisit#</cfoutput>
Dim myCookie As HttpCookie = New 
  HttpCookie("LastVisit")
Dim now as DateTime = DateTime.Now
myCookie.Value = now.ToString()
myCookie.Expires = now.AddDays(10)
Response.Cookies.Add(myCookie)
..
Response.Write(Request.Cookies
  ["LastVisit"].Value)

One additional feature that ASP.NET has that is not present in ColdFusion is the ability to store multiple name/value pairs in a single cookie. You can perform the same operation in ColdFusion, but the code must be written manually, while ASP.NET provides convenient properties and methods on the HttpCookie object to do this for you.

Querying a Database

Database access in .NET is accomplished through the hierarchy of objects collectively known as ADO.NET. A full exploration of ADO.NET is beyond the scope of this paper, so we'll just touch on the most important points. The actual execution of a database query is accomplished with a set of connection, command, parameter and data-adapter objects. There are multiple versions of each of these objects, depending on the type of database being accessed. For example, there is a set for databases with OLE-DB drivers (such as Microsoft Access), as well as a set for databases that have ODBC drivers but lack OLE-DB drivers. There are also specialized data providers for both Oracle and Microsoft SQL Server™ that are optimized to provide high-performance access to each of those specific databases. The examples in this section will use the SQL Server objects, as that is one of the most-commonly-used databases with ASP.NET. The SQL Server objects are located in the System.Data.SqlClient namespace.

In ColdFusion, ad-hoc SQL queries are typically executed with the cfquery tag. Although variables can be inserted directly into the SQL statement with this tag, doing so is not recommended, as this technique is vulnerable to SQL injection attacks, as well as invalid characters invalidating the entire SQL statement. In addition, inserting variables directly into the SQL statement prevents the database server from caching the query execution plan, forcing it to parse the statement anew every time it is executed, which can hurt performance. ColdFusion accounted for this issue by introducing the cfqueryparam tag that works with the cfquery tag to allow for parameterized queries, which can still be built dynamically, but suffer from none of the disadvantages just mentioned. ADO.NET supports both types of queries, but like ColdFusion, parameterized queries are preferred over queries with variables embedded in the SQL statement. Table 14 shows an example of executing a parameterized query in each language.

Table 14. Executing Parameterized Queries

CFML Visual Basic. NET
<cfset sales_cutoff = 1000>
<cfquery name="topSellers " 
  datasource="datasource_name">
SELECT title_id, title, ytd_sales 
  FROM titles
WHERE ytd_sales >= 
   <cfqueryparam
      value="#sales_cutoff#"
      CFSQLType="CF_SQL_INTEGER">
ORDER BY ytd_sales DESC
</cfquery>
Dim sales_cutoff As Integer = 1000
Dim myConnection As SqlConnection = 
  New SqlConnection
    ("connection_string")
Dim myCommand As SqlCommand = 
  myConnection.CreateCommand()
myCommand.CommandText = "SELECT 
  title_id, title, ytd_sales FROM 
    titles WHERE ytd_sales >= 
      @sales ORDER BY ytd_sales 
        DESC"
myCommand.Parameters.Add("@sales", 
  SqlDbType.Int).Value = 
    sales_cutoff
Dim SqlDataAdapter myAdapter = New 
  SqlDataAdapter(myCommand)
Dim topSellers As DataSet = New 
  DataSet()
myAdapter.Fill(topSellers, 
  "titles")

The results of an ADO.NET database query are typically returned in either a DataSet or an IDataReader object. The DataSet is an in-memory data store that resembles ColdFusion's Query object in that it is a copy of the data returned by the database and doesn't require an active connection to the database while it is being used. The IDataReader object is specific to the data provider in use (SqlDataReader, OleDbDataReader, etc.) and represents a live connection to the database that returns data as it's received from the database server. For this reason, the data-reader is read-only, and you cannot navigate backwards through it, but read performance is typically better than that of a DataSet. You must be careful, however, not to tie up the underlying database connection for longer than necessary when using a data-reader.

ColdFusion uses the cfstoredproc, cfprocparam, and cfprocresult tags to execute stored procedures against a database server. In ADO.NET, the code to execute a stored procedure is identical to the code needed to execute a parameterized query, except that you set the SqlCommand object's CommandType to StoredProcedure and the CommandText to the name of the stored procedure to be executed. If we were to imagine a stored procedure equivalent to the query above, the code to call it might look something like the example in Table 15.

Table 15. Calling a Stored Procedure

CFML Visual Basic. NET
<cfset sales_cutoff = 1000>
<cfstoredproc 
  procedure="GetTopSellers"
   datasource="datasource_name">
   <cfprocparam type="in "
      value="#sales_cutoff#"
      CFSQLType="CF_SQL_INTEGER">
   <cfprocresult name="topSellers 
     ">
</cfstoredproc>
Dim sales_cutoff As Integer = 1000

Dim myConnection As SqlConnection =

New SqlConnection

("connection_string")

Dim myCommand As SqlCommand =

myConnection.CreateCommand()

myCommand.CommandType =

CommandType.StoredProcedure

myCommand.CommandText =

"GetTopSellers"

myCommand.Parameters.Add("@sales",

SqlDbType.Int).Value =

sales_cutoff

Dim SqlDataAdapter myAdapter = New

SqlDataAdapter(myCommand)

Dim topSellers As DataSet = New

DataSet()

myAdapter.Fill(topSellers,

"titles")

Although ADO.NET requires slightly more code to do things than ColdFusion does, the benefit lies in greatly increased flexibility and control. For cases in which this additional flexibility is not needed, Microsoft has provided the Data Access Application Block, which encapsulates many common data-access tasks. The result is that you can accomplish the same thing in significantly fewer lines of code, and in fact for many tasks, only a single line of code is required when using this tool.

Outputting Query Data

The typical way to output query data in ColdFusion is to loop over the query results by using cfloop or cfoutput, embedding each row of the data columns directly into some HTML markup. Although this same approach is supported in ASP.NET, many people prefer ASP.NET's powerful and easy-to-use support for databinding. When using databinding, all you need to do is assign some query results to the DataSource property of a data-aware server control (such as the DataGrid), optionally provide some additional formatting information for each column, and call the DataBind() method. The server control will take care of the rest. Many data-aware server controls will provide additional functionality, such as support for paging or in-line editing of the data being displayed. As an example, let's output the query results we got in the previous section, as Table 16 shows.

Table 16. Outputting Query Results

CFML Visual Basic. NET
<table>
<tr>
<th>title_id</th>
<th>title</th>
<th>ytd_sales</th>
</tr>
<cfoutput query="topSellers ">
<tr>
<td>#title_id#</td>
<td>#title#</td>
<td>#ytd_sales#</td>
</tr>
</cfoutput>
<asp:DataGrid id="myDataGrid"

runat="server" />

In page load event:

myDataGrid.DataSource = topSellers
myDataGrid.DataBind()

For more information and examples, please refer to Data Binding Server Controls.

Data Caching and Page Caching

Caching frequently-accessed data can dramatically improve the response time of a site, as the page processing doesn't need to wait on a database query. Caching the HTML generated by a page request can improve response time even more, as the cached page doesn't need to be processed at all. Both ColdFusion and ASP.NET provide support for both caching strategies; however, ASP.NET's support is quite a bit more powerful and flexible than that provided by ColdFusion.

Data Caching

Database query results can be cached in ColdFusion by using the cachedwithin or cachedafter attributes of the cfquery tag. The results of a stored procedure call with cfstoredproc can't be cached with an equivalent mechanism. It's possible to call a stored procedure with cfquery by using a slightly slower provider-specific syntax. Cached queries are differentiated based on the full text of the SQL statement used (along with the other cfquery attributes) and are removed from memory after the specified span of time has elapsed, or when an administrator-defined limit on the number of cached queries is exceeded. Other types of data (arrays, structures, the parsed contents of an XML file) can't be cached in this manner; they must be stored in Application variables where they remain until the ColdFusion service is restarted or they are explicitly removed.

ASP.NET provides a single caching mechanism for any type of data (DataSets, arrays, Hashtables, the parsed contents of XML files) exposed through the Page.Cache object. This object allows for time-based expiration from the cache, as is the case with ColdFusion's query caching, and it adds the ability to expire items based on usage, dependencies, or memory pressure. An example of usage-based expiration might be a cached object that is set to expire from the cache 20 minutes after the last time it is accessed. If this object is accessed every 10 minutes, it will never expire from the cache. On the other hand, if it is not accessed for a long period of time, it will be dropped from the cache to free up memory for more frequently-used items. An example of dependency-based expiration might be some data that is loaded from an XML file. The data can be inserted into the cache with a dependency on the XML file, so that if the XML file ever changes (invalidating the cached data), the loaded data is dropped from the cache immediately.

Cache items can also have dependencies on other cache items. The final method of cache expiration—memory pressure—simply means that the Cache object itself will actively monitor the amount of memory available in the system and the amount of memory taken up by the items it contains. If the available memory in the system gets too low, the Cache object will start removing the least recently accessed items in the cache until it has freed up enough memory to keep the system running smoothly. This process allows ASP.NET to avoid a hard limit on the number of cached items, as ColdFusion has for cached queries. For more information, see the documentation for the Cache object.

Page Caching

Caching the HTML output of a page request is accomplished in ColdFusion with the cfcache tag. Pages can be cached on either the client or the server or both, for a specified span of time, and a different version of each page is cached for each distinct set of URL parameters passed to that page. If the page in question generates different HTML depending on the capabilities of the browser requesting the page, or different text depending on the preferred language of the current user, ColdFusion's page caching scheme can't be used. The reason is that it would return the HTML tailored for the first browser to request the page to all browsers, or the language preferred by the first user to request the page to all users.

The HTML output of a page request can be cached in ASP.NET with the @OutputCache directive. This directive allows the page to be cached on either the client or the server, or both, for a specified span of time. Different versions of the page can be cached based on a combination of many criteria, including one or more specific URL parameters, the browser type and major version requesting the page, one or more HTTP headers (roughly equivalent to ColdFusion's CGI variables), or the output of a custom function that uses whatever criteria you code it to use. This flexibility allows ASP.NET's page caching to be used in many situations in which ColdFusion's page caching falls down.

In addition to full-page caching, ASP.NET also includes support for partial-page caching. The HTML output by a custom user control can be cached based on most of the same criteria supported by full-page caching, with the addition of allowing different versions of a control's output to be cached for different values of one or more of that control's properties.

For more information about ASP.NET's output caching, see Caching ASP.NET Pages.

Server-Side HTTP Requests

Making an HTTP request from the server can be done with the cfhttp tag in ColdFusion, and with the System.Net.WebClient object in ASP.NET, as Table 17 shows.

Table 17. HTTP Requests

CFML Visual Basic. NET
<cfhttp 
  url="http://www.macromedia
    .com/" method="GET">
</cfhttp>
<cfoutput>#HTMLCodeFormat(CFHTT
  P.FileContent)#</cfoutput>
Dim myWebClient As System.Net.WebClient
myWebClient = New System.Net.WebClient()
Dim buffer As Byte()
buffer = 
  myWebClient.DownloadData
    ("https://www.microsoft.com/")
Dim content As String
  content = System.Text.Encoding
    .UTF8.GetString(buffer)
Response.Write(Server.HtmlEncode
  (content))

XML Parsing and Manipulation

Built-in support for parsing and manipulating generic XML is new in ColdFusion MX, and although it is very easy to use, certain advanced capabilities are lacking. For example, ColdFusion MX lacks support for XML namespaces, XML Schema Definition (XSD) validation, using parameters in XSLT transformations, and reading and writing large XML documents without loading the entire document into memory.

The .NET framework has extremely comprehensive support for XML and related technologies, and full coverage of this support is beyond the scope of this paper. A good starting place would be Employing XML in the .NET Framework.

Summary

A migration from ColdFusion to ASP.NET can be as simple or as complex as it needs to be. Your migration could be a straightforward port of existing functionality or a complete rewrite that takes full advantage of ASP.NET's advanced features. Nearly every feature present in ColdFusion has an equivalent in ASP.NET, which facilitates a straight port that requires very little effort beyond basic syntax translation. However, if time constraints allow, a re-examination of the application's architecture (in light of ASP.NET's unique capabilities), can lead to a significant improvement in the application's performance, scalability and functionality.

© Microsoft Corporation. All rights reserved.