Using the ASP to ASP.NET Migration Assistant
Overview
In this article you will learn how to use the ASP to ASP.NET Migration Assistant to help move your existing ASP code base to ASP.NET in order to take
advantage of the many benefits provided by the Microsoft .NET Framework.
Moving to ASP.NET is generally accomplished in two stages. First you port the
existing ASP application to ASP.NET and then you can optimize the application
to fully leverage the .NET Framework. This article covers the initial migration
using the Migration Assistant to partially automate the first stage.
Code Sample:
The Downhill Bikes code sample and the ASP to ASP.NET Migration
Assistant for this paper are available from
http://www.asp.net/migrationassistants/asp2aspnet.aspx
ASP.NET Web Programming Model
The ASP.NET programming framework provides a different Web development
model than traditional ASP as well as a different execution process. The HTML
and script blocks in traditional ASP pages are interpreted as they are
encountered top to bottom. By contrast, ASP.NET pages are compiled into classes
and code is executed in response to events such as Page Load. This
event-driven execution model is similar to the execution model of VB6
applications.
ASP.NET pages use .aspx as a file extension instead of .asp. The
content of an ASPX file is compiled into a class the first time it is
requested. This class gets its generic Web form functionality from the base
class System.Web.UI.Page.
Every ASP.NET Web form must inherit from the Page class directly or indirectly
via some other base class that inherits from Page.
Your Web forms can inherit from any class that ultimately derives
from Page.
That is how ASP.NET "code-behind classes" work. The code-behind
class inherits from Page and then the Web form inherits from the
code-behind class. This is the default way that Visual Studio .NET 2003 creates
ASPX Web forms, allowing your ASPX files to contain only markup and client-side
script while the code-behind classes contain all the programmatic logic for
manipulating the user interface and interacting with business objects.
Code-behind classes are completely optional for Web forms. You
can write standalone ASPX pages that contain both markup and server-side
programming logic including event handlers such as Page_Load. With standalone
ASPX pages you can create Web forms that are structured more like classic ASP
pages. The Migration Assistant creates standalone ASPX pages when it converts
an ASP application to ASP.NET.
Despite the significantly enhanced execution model in ASP.NET, a
considerable amount of legacy ASP code is also valid ASP.NET code that can be
compiled and executed by the Microsoft ASP.NET engine. ASP.NET applications (written
in Visual Basic .NET) support a significant amount of the syntax common in ASP applications
(written in VBScript). Much of the incompatible syntax can be converted to new
syntax by the ASP to ASP.NET Migration Assistant, greatly reducing the overall
cost of migrating an application to ASP.NET.
Mitigating the Migration Mountain
Moving a code base to a new application platform is rarely a minor
task. However the extensive backward compatibility support built into ASP.NET allows simple ASP pages to run as ASP.NET pages with little more than adding an x to
the file extension. For nontrivial ASP pages there will generally be a varying
number of simple changes required for the legacy code to run as an ASP.NET application.
The majority of ASP applications do not have to be re-architected
to run as ASP.NET applications. Most of the required changes are simply
because of VBScript syntax that is not supported in Visual Basic .NET. Among the most prominent examples are the use of default properties and the
Set keyword.
VBScript supports default properties for objects and uses the
Set keyword
to differentiate between an identifier referring to an object and an identifier
referring to an objects default property. In Visual Basic .NET, an object identifier is always a reference to the object itself. This change in
behavior makes the
Set keyword irrelevant in Visual Basic .NET but also requires property access to be fully qualified. For example,
rs.Fields("fldName").Value.
However, an object can have a default indexed property such as the
Fields collection,
so in Visual Basic .NET your can also use rs("fldName").Value.
One of the major advantages of Visual Basic .NET over VBScript is
the ability to use strongly typed variables. VBScript variables are always
implicitly of the type Variant. The rough equivalent in Visual Basic .NET is
the Object data type. A variable declared without an explicit data type is
implicitly declared as Object. Without a data type, the compiler is unable to
verify the methods and properties that are valid for a variable. This
verification has to happen at runtime, causing your application to incur extra
runtime processing and increasing the risk of runtime errors related to data
types. Strongly typed variables for primitive types such as Integer are also
more efficient than Object variables used to hold primitive type values (called
value types in the .NET Framework). For both performance and
maintainability reasons, your Visual Basic .NET code should use strongly typed
variables. To this end, the Migration Assistant will attempt to determine the
correct data type for a variable whenever possible.
Many ASP applications have business and data access logic
encapsulated in COM components. ASP.NET applications can call COM components,
which means that the entire legacy code base from an ASP application does not
have to be migrated in order to move to ASP.NET. Logic in COM components can
be migrated to .NET components piecemeal or not at all. There is a performance
penalty whenever you cross from the .NET world into the COM world (through COM
Interop). If you are calling into COM objects frequently in a given page
request you should consider rewriting those COM objects, or at least wrapping
the COM object so that as much work as possible is done each time you move into
the COM world.
The sample application that will be ported to ASP.NET in this
article uses COM components for features such as a shopping cart and order
processing. Those COM components are migrated to .NET components in a
subsequent article on optimizing your site after the initial migration.
Sample Application: Downhill Bikes ASP
Downhill Bikes is a Web application for a fictitious online
retailer. The Downhill Bikes site includes a product catalog with search
capabilities, a shopping cart, and user login. The presentation layer consists
of ASP pages that call COM business objects. The COM objects use ADO to communicate with a SQL Server 2000 database.
.gif)
Figure 1. Downhill Bikes Web site default page
|
Layer
|
Page / Component |
Description |
Uses / Includes |
|
UI / Presentation
|
default.asp |
Displays catalog contents and shopping cart summary. Provides
shopping cart updating. |
Catalog
_common.asp |
|
login.asp |
Accepts and verifies user credentials. |
Customer
_common.asp |
|
checkout.asp |
Displays order confirmation and processes order. |
Catalog
_common.asp
_verify_login.asp
_order.asp |
|
thankyou.asp |
Displays thank you after placing an order. |
_common.asp |
|
search.asp |
Provides search interface and displays catalog search results.
|
Catalog |
|
_common.asp |
Provides common functions and constants. |
|
|
_order.asp |
Provides functions for processing an order. |
Order |
|
_verify_login.asp |
Provides common code for checking user login status and
redirecting to login page. |
|
|
|
|
|
|
|
Business Logic
|
Catalog |
Provides catalog product and category data to the presentation
layer. |
Db
Helpers
Util |
|
Customer |
Provides customer data to the presentation layer. |
Db
Helpers
Util |
|
Order |
Provides functions for adding orders to the database.
|
Db
Helpers
Util |
|
Helpers |
Provides additional helper functions for the Catalog, Customer,
and Order components. |
|
|
Db |
Provides database helper functions for the Catalog, Customer,
and Order components. |
Util |
|
Util |
Provides additional helper functions for parsing and encoding
data. |
|
|
|
|
|
|
|
Data |
|
SQL Server database including several stored procedures
|
|
Figure 2. Overview of Downhill Bikes tiers
Capabilities of the Migration Assistant
The ASP to ASP.NET Migration Assistant automates a number of the
steps required to port an ASP site to ASP.NET. The Migration Assistant updates
the file extensions from .asp to .aspx and corrects references to these files
in the application such as in include directives, hyperlinks,
Response.Redirect statements,
and HTML form action attributes. [Note: Files included via include directives
are treated as ASP files and updated to ASP.NET syntax regardless of the actual
extension on the included file.]
The Migration Assistant also analyzes VBScript to help deal with
undeclared and late bound variables. VBScript commonly contains variables that
are never declared explicitly. The Migration Assistant adds declarations for
variables and includes the appropriate data type in cases where the data type
can be inferred. Identifying the data types for objects allows the Migration
Assistant to identify the explicit property to be accessed in cases where the
original code was accessing a default property. Adding a data type to the
declaration also allows for early binding, which adds to the already improved
performance story for your migrated application. Early binding also means that
a whole class of errors is moved from runtime to compile time. [Remember that inline
code in ASPX pages (i.e., code in <% %> and
<script
runat="server"> blocks in the .aspx file), is
not compiled until the first time a page is accessed.]
ASP.NET has different behavior and rules for render blocks (<% %>)
and server script tags (<script runat="server">).
The Migration Assistant moves all function, subroutine, and global variable
declarations into a single server script tag. The Migration Assistant only
deals with server script blocks written in VBScript. Script blocks written in
other languages are marked with an error warning message.
For more information on exactly what the ASP to ASP.NET Migration
Assistant can do and cannot do, see the Getting Started guide at
http://www.asp.net/migrationassistants/GettingStarted_ASPtoASPNET.htm.
Migrating Downhill Bikes
Run the Migration Assistant
The Migration Assistant can be run from the command line
(AspUpgrade.exe) or from within Microsoft Visual Studio .NET 2003. To start
the ASP to ASP.NET Migration Assistant from Visual Studio .NET 2003, select the
File | Open | Convert menu command and follow the instructions in the
dialog windows. The Migration Assistant Wizard walks you through selecting the
source ASP code, the target directory for the migrated site, and the name for
the migrated application (which the Migration Assistant makes the root
namespace for the new project). In this article, the migrated application is
called DownhillBikesMigrated.
.gif)
Figure 3. Convert menu for starting the Migration Assistant
After the Migration Assistant finishes upgrading your site, a
conversion report is added to your Visual Studio .NET 2003 project that
outlines issues identified by the Migration Assistant that you should review.
.gif)
Figure 4. Conversion report
Bear in mind that this conversion report does not cover all the
migration issues. There are a number of things that cannot be automated that
will require a good working knowledge of ASP, ASP.NET, and the application
design to correct. In many cases there will be a number of small issues to
resolve just to get the site to run.
The Migration Assistant has now completed its role in converting
Downhill Bikes to ASP.NET. The .asp files have been changed to .aspx files and
the VBScript has been converted to Visual Basic .NET. The Visual Basic .NET
code in each ASPX page has been grouped into one <script> block that
includes variable declarations for previously undeclared variables, including data
types for variables if they could be determined. Any COM components that were
being used in the original site, including ADO classes such as
Recordset,
are still used in the migrated site.
Attempt to Browse the Site
After migrating Downhill Bikes, set default.aspx as the start
page by right-clicking on default.aspx in the Solution Explorer and selecting Set
As Start Page. Then press Ctrl+F5 to run the site.
Caveat: The version of the Migration
Assistant used with this article contained a bug that caused some commented
code to be partially converted. If you get a Parser Error when you try to view
the site, simply delete the contents of global.asax. In the original Downhill
Bikes site, global.asa contains only comments inside a <script> block.
The default page works perfectly after the migration. You can
select categories, select a product, add a product to your shopping cart,
adjust the shopping cart contents, and proceed to the checkout. Although the
Migration Assistant has already done most of the work at this point, there are
still a few problems to fix in Downhill Bikes before the site will run properly.
When you attempt to login on your way to the checkout, an exception is thrown:
.gif)
Figure 5. InvalidCastException
For a larger application, it would make sense at this point to
move code into code-behind classes to facilitate the debugging process. For
Downhill Bikes, the changes are trivial and easily handled by examining the ASP.NET runtime error messages.
Finishing the Migration
Correcting Data Type Problems
The first runtime error encountered is an invalid cast. The
problematic line of code is:
userInfo = cust.GetDetails(customerID)
If you look at the variable declaration for
userInfo as
created by the Migration Assistant, you see that it has been declared as an
array of Integer:
Dim userInfo() As Integer
What is not immediately obvious by examining the ASPX page is
that cust.GetDetails actually
returns an array of Variant. This would have been easily identified
if you had access to the source code for GetDetails. However,
this is often not the case, especially when working with third-party components.
In those situations, a bit of detective work is required to workaround a
migration issue. In this case it is reasonable to assume that the customer
data being returned is not a set of integers so the Migration Assistant must
have improperly inferred the data type. Simply changing the array data type to
Object will correct the problem:
Dim userInfo() As Object
After successfully logging into Downhill Bikes, a second problem immediately
arises in checkout.aspx:
.gif)
Figure 6. OverflowException
Once again the problem is caused by an incorrect data type. This
time the Migration Assistant has incorrectly inferred that subtotal should be
of the data type Byte. Changing the variable
declaration to Double will prevent an overflow exception:
Dim subtotal As Double
This same data type error, Dim subtotal As Byte,
also shows up in _common.aspx and is fixed the same way.
Working around STA Components
The final issue to resolve is also in checkout.aspx. The
getUniqueNumber function
in checkout.aspx generates a unique identifier using a COM component that executes
only in a single-threaded apartment (STA). Normally ASP.NET uses multithreaded
apartment (MTA) threading when accessing COM components. As a result, the
checkout page causes an exception because the STA component cannot be created.
To use an STA component, you must add the AspCompat="true" attribute
to the @Page directive.
Alternatively you can replace the STA COM component with managed
code. In this case, you can use the System.Guid class from
the .NET Framework class library to generate a GUID instead of a COM
component. So this line:
guid = server.CreateObject("scriptlet.typelib").guid
Can be replaced with this:
guid = System.Guid.NewGuid.ToString()
Ready to Run
The migrated Downhill Bikes application is now ready to run. All
of the functionality is working, which includes: browsing and searching the
catalog; adding items to the shopping cart; clearing the shopping cart;
updating quantities in the shopping cart; proceeding to the checkout; logging
in; and placing an order.
Other Migration Issues
This article covers the migration tasks required to port the
Downhill Bikes ASP application to ASP.NET. There are certainly other migration
tasks that will be required for other applications. The following sections are
examples of issues that you may have to deal with manually.
Default Properties
When the Migration Assistant examines your code, it may not be
able to determine the correct data type for variables or one variable might be
used to hold values and objects of numerous types. In these cases, the
Migration Assistant cannot add explicit access for default properties so your
code might not run or it might not behave as desired. Consider the following
ASP code:
Set s = CreateObject("ADODB.Connection")
s.ConnectionString = "Data Source=(local);Database=Northwind;..."
Response.Write s
Set s = CreateObject("ADODB.Recordset")
In the preceding code, the variable s is used to hold a
Connection object
and then a Recordset object. When the ASP to ASP.NET Migration
Assistant converts this code, the variable will be declared as
Object.
In the converted Response.Write statement, the default
ConnectionString property
of the Connection object
is not added as required to obtain identical functionality in the ASP.NET
application:
<%@ Import namespace="ADODB" %>
<script language="VB" runat="Server">
Dim s As Object
</script>
<%
s = New ADODB.Connection
s.ConnectionString = "Data Source=(local);Database=Northwind"
Response.Write(s)
s = New ADODB.Recordset
%>
The correct statement in the migrated code would be:
Response.Write(s.ConnectionString)
Dates in DD/MM/YYYY Format
ASP allows you to express date literals in numerous formats
including the DD/MM/YYYY format. The following date literal in VBScript is
parsed as December 25, 2010:
<%
xmas = #25/12/2010#
%>
Working with short date formats has been an ongoing problem for
many organizations wishing to use alternate formats such as DD/MM/YYYY since month-day-year
ordering is assumed when the digits in a date literal make the format ambiguous
(e.g., 01/04/1999 is assumed to be January 4, not April 1.).
To help mitigate date parsing problems across different cultures,
the .NET Framework expects all date literals to be in MM/DD/YYYY format. The
first release of the ASP to ASP.NET Migration Assistant does not properly
convert date literals in alternate formats such as DD/MM/YYYY and YYYY/MM/DD to
the expected MM/DD/YYYY format. For example, the Migration Assistant produces
the following incorrect code from the xmas example shown above.
The variable is incorrectly declared as Short and the date
literal is converted into a sequence of division operations:
<script language="VB" runat="Server">
Dim xmas As Short
</script>
<%
xmas =25/12/2010
%>
Include Directives in Subroutine Definitions
The ASP to ASP.NET Migration Assistant does a good job of
intelligently converting include files. But there are some situations in which
the Migration Assistant does not generate the expected output. Consider the
following contents of an ASP include file:
<%
Set conn = Server.CreateObject("ADODB.Connection")
conn.ConnectionString = "TEST CONNECTION STRING"
%>
When the include file is included in an ASP page between two render
blocks that define a subroutine, the code in the include file is processed as
part of the body of the subroutine. In the following example, the code from the
include file creates the connection object and sets its
ConnectionString property.
The Response.Write statement
then outputs the value of the ConnectionString.
<%
Sub TestingInclude()
%>
<%
Response.Write conn.ConnectionString
End Sub
%>
<% TestingInclude %>
When this code is ported to ASP.NET by the Migration Assistant,
the TestingInclude subroutine
is not converted as expected:
<%@ Import namespace="ADODB" %>
<script language="VB" runat="Server">
Sub TestingInclude()
Dim conn As ADODB.Connection
Response.Write("" & vbCrLf)
Response.Write(" <!-- #INCLUDE FILE=""inc.aspx"" -->")
Response.Write("" & vbCrLf)
Response.Write("")
Response.Write(conn.ConnectionString)
End Sub
</script>
<%TestingInclude()%>
Rather than incorporating the code from the include file, the
Migration Assistant has generated Response.Write statements
that output the include directive (and the surrounding whitespace). The
include directive is obviously not processed in this case but sent to the
client where it will be interpreted as an HTML comment.
The ASP to ASP.NET Migration Assistant is a powerful tool for porting
ASP sites to ASP.NET but it is not a "silver bullet" solution. Extensive
code review and testing should be considered mandatory before deploying a
migrated application.
Conclusion
This article covered the first migration stage for porting the
Downhill Bikes ASP application to ASP.NET. The ASP to ASP.NET Migration
Assistant automates a number of common migration tasks so migrating Downhill
Bikes can be done quite quickly. The application has 100% functionality after
this migration and immediately benefits from several ASP.NET features. But
this site is not yet optimized to take advantage of many other .NET Framework
and ASP.NET features such as ADO.NET, server controls, data binding, caching,
paging, authentication, and more. Optimizing the migrated Downhill Bikes is
covered in a follow-up to this article.
Additional Information
ASP to ASP.NET Migration Assistant Getting Started Page
http://www.asp.net/migrationassistants/GettingStarted_ASPtoASPNET.htm
ASP to ASP.NET Migration Assistant Forum
http://www.asp.net/migrationassistants/forums
Converting ASP to ASP.NET
http://msdn.microsoft.com/library/en-us/dndotnet/html/convertasptoaspnet.asp
Migrating ASP Pages to ASP.NET (SDK Documentation)
ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1033/cpguide/html/cpconmigratingasppagestoasp.htm