Legacy Code – Dealing with Classic ASP

Summary

I’ve written quite a few blog posts about legacy code.  In this blog post I’m going to discuss how you can deal with classic ASP, why you should deal with it sooner than later and some details of what to do.

Classic ASP

If you’re running a .Net shop, Classic ASP is about the most difficult monster to deal with.  Off the top of my head, I can list a few disadvantages to having one or more asp pages mixed in with your .Net code:

  • ASP executes under the IIS app pool pipeline type of “Classic” and will not work well with the “Integrated” managed pipeline mode.
  • ASP has it’s own session management.  If you mix ASP with .Net, you’ll end up with two different session storage mechanisms.
  • ASP does not have a compiler.  Bugs are only discovered during run-time.
  • ASP does not have a robust unit testing capability.
  • ASP is rarely written in a modular fashion.  Object oriented design can be used but rarely is.
  • ASP is not supported by Microsoft increasing the likelihood that a future version of IIS might not support it.
  • ASP contains config settings in the global.asa and does not recognize the web.config file.

The behavior of an ASP page is similar to JavaScript.  You can change it on the fly and not have to worry about re-compiling it.  This is only a minor advantage considering the fact that you must test all features in run-time.

Eliminating Classic ASP pages

Your first goal should be to eliminate these pages.  Here is a list of advantages to eliminating all ASP pages in your product:

  • Finding qualified software developers will be easier.  ASP knowledge is rare and becoming rarer.
  • Non structured ASP code is very difficult to work with.  Development time can be reduced by converting to .Net.
  • .Net code can have unit tests added.
  • Compile time bugs can be identified before code is released.
  • Memory and performance profiling tools work with .Net.
  • Refactoring tools work with .Net, reducing errors when variables are renamed.
  • You can combine your config settings to the web.config file.
  • Visual Studio will auto-indent VB.Net code reducing coding errors.

Some disadvantages of eliminating ASP pages in your product could be:

  • It costs money/man-hours to convert the code.  The amount can vary depending on the level of conversion.
  • Converting the code will cause bugs, translating to a degradation of customer satisfaction.

Levels of Conversion

There are different levels of converting code.  The level depends on how far you wish to go with the conversion.  The easiest level to eliminate ASP is to convert it directly to Visual Basic .Net.  No special translation, no real cleanup of code, just convert as directly as possible.  You’ll end up with the same spaghetti as before, except you can now compile it together with your existing code.  No new features are created when performing this type of conversion.

The next level is to convert and cleanup.  This level involves converting to VB.Net and then maybe consolidating your common functions (from ASP) with your existing common objects and methods.  This usually occurs if you have a database driven web application.  If you have a mixture of .Net and ASP code, you’ll end up with two sets of common database wrappers.  Merging these together will reduce your code and if your .Net objects are unit tested, you now have a more robust set of database functions.  This level of conversion is difficult and can take a lot of time because your common objects/functions are probably going to be alien to each other.  There will be a lot of refactoring of pages to use the common .Net objects.  No new features are created in this type of conversion.

The next level is to convert into another language such as C#.  I’m assuming your system has a mixture of ASP and C# and possibly VB.Net.  If you plan to convert to C#, this will be a difficult task.  C# syntax alone is not close to ASP syntax like VB.Net is.  The hazard of doing your conversion this way is that you’ll cause a lot of bugs that your customers will notice without gaining any new features.

The next level of conversion is the replacement.  This is where you redesign and replace your ASP code with completely new code.  This is very long term and hazardous.  You’ll probably need to live with your ASP for years before you can replace the code with new systems.  The advantage of this method is that the conversion is buried into the work of creating new features.  Customers will attribute bugs with the new code (since there will be bugs in the new code), but there will also be challenges with integrating with existing ASP legacy code.

Converting from ASP directly to VB.Net

Let’s pretend that you’ve settled on converting your ASP into .Net as quickly and as cheaply as possible.  Now you need to take inventory of your ASP pages and you’ll need to plan which pages you’re going to convert first.  I would recommend converting a few smaller pages just to get the feel of it.  You might want to determine what the maximum number of converted pages per release will be.  This will probably depend on developer effort and QA effort.  You could break it into systems and deploy one system of converted pages at a time.  If you have on-going enhancements, then ignore any pages that are about to be replaced by any new subsystem.  Convert those last if necessary.

Once you’ve identified your pages, you’ll notice that there are some common functions that are probably contained in included ASP pages.  Those will need to be converted to .Net first.  You should define a unique namespace for all of this legacy code so that your functions, which will be converted to objects and methods don’t collide with any existing .Net code.

Converting an ASP Page

Let’s get down to some details.  An ASP page typically consists of a collection of programming languages crammed into one source file with switches that indicate where one language starts and another stops.  Here’s an example:

<% Option Explicit %>
<!--#include virtual="/common/myutil.asp"-->
<%
Dim sSQL, rsTemp, dbConnect
Dim action, note, id

If Not checkPageRights("MyPage") Then Response.Redirect("/denied_access.asp")

id = Trim(Request("id"))

If Request("add")<> "" and trim(Request("id")) <> "" then

  '-- Adding a new user
  '-- some asp code here
End If

' Read list
sSQL = "query_for_list " & dbid(id)
executeSQLStatement sSQL, id, rsTemp, dbConnect

%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
  <title>List</title>

  <style type="text/css">
  body {
    margin: 5px 5px;
    background: #FFFFFF;
  }
  </style>
  <!--#include virtual="/js/jquery_stuff.js" -->
</head>
<body>


<table>
  <tr>
    <td>name</td><td>age</td>
  </tr>
  <% While NOT rsTemp.EOF %>
    <tr><td><%=rsTemp("name") %></td><td><%=rsTemp("age") %></td></tr>
  <% Wend %>
</table>

<script language='javascript' type='text/javascript'>
function ConfirmDel() {
  if (confirm("Are you sure you want to delete this record.  Press OK to delete."))
    return (true);
  else
    return (false);
  };
</script>

</body>
</html>

You’ll need to cut any Javascript and HTML and put it into the front-side page of a VB.Net web form.  Some code that works in ASP will not work with the VB.Net front-side page.  For that code, you’ll need to put the code in a method and call the method from the front-side code.  You might even need to go as far as writing the code from the code-behind page.

All functions will need to have parenthesis added to them.  The “executeSQLStatement” will need to be converted to: “executeSQLStatement(sSQL, id, rsTemp, dbConnect)” in order to compile.

As I mentioned earlier, you’ll need to convert any included files first.  That means that the “myutil.asp” page at the top will need to be converted to VB.Net first.  You can convert the entire file, or just convert common functions that are used in this page.  The advantage of doing it peacemeal is that you’ll end up removing any dead-code while you’re converting.  You can also include your job of testing common code with the pages that you are converting.  As you continue to convert more difficult pages, you should have most of your common functions converted into objects/methods.

Here are a few conversions you’ll need to be aware of:

  • Convert any line wrapping “&_” into a “& _”.  VB.Net expects a space between the ampersand and the underscore.
  • Add parenthesis to your function calls if needed.
  • “Wend” converts to “end while” in VB.Net.
  • isNul() converts to “Is Nothing”.
  • “Date” converts to “DateTime.Now()”
  • Remove any “set” statements.
  • Add “.Value” to recordset variables.  rs(“lastname”) becomes rs(“lastname”).Value

Microsoft has a good site for conversion tricks: Converting ASP to ASP.NET.  I would recommend reviewing this information before starting.

Next, ASP code will go into the code-behind page.  That would be this section of code:

Dim sSQL, rsTemp, dbConnect
Dim action, note, id

If Not checkPageRights("MyPage") Then Response.Redirect("/denied_access.asp")

id = Trim(Request("id"))

If Request("add")<> "" and trim(Request("id")) <> "" then

  '-- Adding a new user
  '-- some asp code here
End If

' Read list
sSQL = "query_for_list " & id
executeSQLStatement sSQL, id, rsTemp, dbConnect

You’ll need to make sure that any variables that are used in the front-side code are declared globally in the code-behind.  You’ll also need to determine the data types and add those.

After You Convert a Page

When you have completed your raw conversion, you’ll probably execute the page and see how it compiles and runs.  Fix any obvious bugs.  Does it run slower?  If so, then something is wrong.

I would recommend running a memory profiler at least once to see if there are any memory leaks.  Classic ASP can handle some memory management better than VB.Net and some things are worse.  Database connections are handled a bit better in ASP.  You’ll need to make sure your database connections are closing when your web page is finished.  If not, then you’ll need to track down where to put in a close statement.  I usually open up a studio window into MS SQL and execute the following query to determine how many connections are currently open:

SELECT
  DB_NAME(dbid) as DBName,
  COUNT(dbid) as NumberOfConnections,
  loginame as LoginName
FROM
  sys.sysprocesses
WHERE
  dbid > 0
GROUP BY
  dbid, loginame

Then run your web page a few times and see if the numbers increase.  You’ll need to have a local database that only you are using in order for this step to be effective.

I would also recommend purchasing a tool such as ReSharper.  You’ll discover variables that are not used.  When your page works, remove all the unused variables.  Reduce the clutter.

Upon completion of your page conversions you can change your IIS server to use the Integrated managed pipeline.  Make sure you perform a regression test after this has been switched.

Finally

If your system has hundreds of Classic ASP pages you can script some of the conversion.  I would make a list of common functions and then create a script or program that can search a designated source file and check for missing parenthesis.  Encode as many of the conversion rules as possible in your script to handle the bulk of the conversion before you move the code to your .Net source file.

Name your .Net source the same as your asp file (you’ll end up with extensions like .aspx, .aspx.designer.vb and .asp.vb which do not collide with .asp extensions).  Once you have replaced an ASP page, be sure to map out any links to that page in your application to the new page.  I would also recommend changing the ASP extension to something like .asp.done so you can catch any missed mappings in your application while you are testing.

Leave a Reply