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 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 attributes bugs with the new code (since they will be bugs in the new code), but there will also be difficulty 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.  In 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.

Any 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.

 

The Trouble with Legacy Code

It’s been a long time since I wrote about legacy code.  So I’m going to do a brain-dump of my experience and thoughts on the subject.

Defining Legacy Code

First, I’m going to define what I mean by legacy code.  Many programmers who have just entered the industry in the past 5 years or less view legacy code as anything that was written more than a year ago or code that was written in the previous version of Visual Studio, or the previous minor version of .Net.  When I talk about legacy code, I’m talking about code that is so old that many systems cannot support it anymore.  An example is Classic ASP.  Sometimes I’m talking about VB.Net.  Technically, VB is not a legacy language, sometimes it is.  In the context of VB.Net I’m really talking about the technique used to write the code.  My experience is that Basic is a language that is picked up by new programmers who have no formal education in the subject or are just learning to program for the first time.  I know how difficult it is to ween yourself off your first language.  I was that person once.  Code written by such programmers usually amounts to tightly coupled spaghetti code.  With all the accessories: no unit tests, ill defined methods treated like function calls, difficult to break dependencies, global variables, no documentation, poorly named variables and methods, etc.  That’s what I call legacy code.

The Business Dilemma

In the business world the language used and even the technique used can make no difference.  A very successful business can be built around very old, obsolete and difficult to work with code.  This can work in situations where the code is rarely changed, the code is hidden behind a website or the code is small enough to be manageable.  Finally, if the business can sustain the high cost of a lot of developers, QA and other support staff, bad code can work.  It’s difficult to make a business case for the conversion of legacy code.

In most companies software is grown.  This is where the legacy problem gets exponentially more costly over time.  Most of the cost is hidden.  It shows up as an increased number of bugs that occur as more enhancements are released (I’m talking bugs in existing code that was disturbed by the new enhancement).  It shows up as an increase in the amount of time it takes to develop an enhancement.  It also shows up as an increase in the amount of time it takes to fix a bug.

Regression testing becomes a huge problem.  The lack of unit testing means the code must be manually tested.  Automated testing with a product like Selenium can automate some of the manual testing, but this technique is very brittle.  The smallest interface change can cause the tests to break and the tests are usually too slow to be executed by each developer or to be used with continuous integration.  

What to do…

Add Unit Tests?

At first, this seems like a feasible task.  However, the man-hours involved are quite high.  First, there’s the problem of languages like Classic ASP.  Unit tests are just not possible.  For code written in VB.Net, dependencies must be broken.  The difficulty of breaking dependencies is that refactoring can be complicated and cause a lot of bugs.  It’s nearly impossible to make a business case to invest thousands of developer hours into the company product to produce no noticeable outcome for the customer.  Even worse, is if the outcome is an increase in bugs and down-time.  The opposite of what is intended.


Convert Code?

Converting code is also very hazardous.  You could theoretically hold all enhancements for a year, and throw hundreds of programmers at the problem of rewriting your system in the latest technology with the intent to deliver the exact user experience currently in place.  In other words, the underlying technology would change, but the product would look and feel the same.  Business case?  None.

In the case of Classic ASP there are a couple of business cases that can be made for conversion.  However, the conversion must be performed with minimal labor to keep costs down and the outcome must be for the purpose of normalizing your system to be all .Net.  This makes sense if your system consists of a mix of languages.  The downside of such a conversion is the amount of regression testing that would be required.  Depending on the volume of code your system contains, you could break this into small sections and attack it over time.

One other problem with conversion is the issue of certification.  If you are maintaining medical or government software that requires certification when major changes take place, then your software will need to be re-certified after conversion.  This can be an expensive process.


Replace when Possible?

This is one of the more preferred methods of attacking legacy code.  When a new feature is introduced, replace the legacy code that is touched by the new feature with new code.  This has several benefits: The customer expects bugs in new features and the business expects to invest money in a new feature.  The downside of using only this technique is that eventually, your legacy code volume will plateau because of web pages that are little used or are not of interest for upgrading (usually it’s the configuration sections that suffer from this).

A downside to this technique is the fact that each enhancement may bring new technologies to the product.  Therefore, the number of technologies used over time grows.  This can be a serious liability if the number of people maintaining the system is small and one or more decide to move on to another company.  Now you have to fill the position with a person that knows a dozen or more odd technologies or the person to be hired will need a lot of time to get up to speed.


The Front-End Dilemma

Another issue with legacy code that is often overlooked is the interface itself.  Over time, interfaces change in style and in usability.  Many systems that are grown end up with an interface that is inconsistent.  Some pages are old-school html with javascript, others use bootstrap and AngularJS.  Many versions of JQuery are sprinkled around your website.  Bundling is an add-on if at all.  If your company hires a designer to make things consistent looking, there is still the problem of re-coding the front-end code.  In Classic ASP, the HTML code is always embedded in the same source file as the Javascript and VB Script.  That makes front-end conversion into a level 10 nightmare!  .Net webpages are not picnic either.  In my experience VB.Net webpages are normally written with a lot of VB code mixed in the front-side code instead of the code-behind.  There are also many situations where code behind emits html and javascript to allow logic to decide which code to send to the customer’s browser.


The Database Dilemma

The next issue I want to mention is the database itself.  When Classic ASP was king in the world of developing Microsoft product based websites, the database was used to perform must of the heavy lifting.  Websites did not have a lot of power and MS SQL had CPU cycles that could be used for processing (most straight database functions tax the hard drive but leave the CPU idle).  So many legacy systems will have the business logic performed in stored procedures.  In this day and age, it becomes a license cost issue.  As the number of customers increase, instances of databases must increase to handle the load.  Web servers are much cheaper to license than SQL servers.  It makes more sense to put the business logic in the front end.  In today’s API driven environment, this can be scaled to provide CPU, memory and drive space to the processes that need them the most.  In legacy systems, the database is where it all happens and all customers must share the misery of one heavy-duty slow running process.  There is only one path for solving this issue.  New code must move the processing to a front-end source, such as an API.  This code must be developed incrementally as the system is enhanced.  There is no effective business case for “fixing” this issue by itself.

As I mentioned, a lot of companies will use stored procedures to perform their back-end processing.  Once a critical mass of stored procedures have been created, you are locked into the database technology that was chosen from day one.  There will be no cost effective way to convert an MS SQL database into Mongo or Oracle or MySQL.  Wouldn’t it have been nice if the data store was broken into small chunks hidden behind APIs?  We can all dream right?


The Data Center Dilemma

Distributed processing and scalability are the next issue that come to mind.  Scaling a system can consist of adding a load-balancer with multiple web servers.  Eventually, the database will max out and you’ll need to run parallel instances to try and split the load.  The most pain will come when it is necessary to run a second data center.  The decision to use more than one data center could be redundancy or it could be to reduce latency to customers located in a distant region.  Scaling an application to work in multiple data centers is no trivial task. First, if fail-over redundancy is the goal then the databases must be upgraded to a enterprise licenses.  Which increases the cost of the license, but also doubles that cost because the purpose is to have identical databases at two (or more) locations.

Compounding the database problems that will need to be solved is the problem of the website itself.  More than likely, your application that was “grown” is a monolithic website application that is all or nothing.  This beast must run from two locations and be able to handle users that might have data at one data center or the other.  

If the application was designed using sessions, which was the prevailing technology until APIs become common, then there is the session fail-over problem.  Session issues will rear their ugly head when a web-farm is introduced, but there are cheap and dirty hacks to get around those problems (like fixing the incoming ip to a web server to prevent a user from going to another web server after they log in).  Using a centralized session store is a solution to a web farm.  Another solution is the use of a session-less website design.  Adapting a session-based system to session-less is a monstrous job.  For a setup like JWT, the number of variables in a session must be reduced to something that can be passed to a browser.  Another method is to cache the session variables behind the scenes and pass a token to the browser that identifies who the user is.  Then the algorithm can check to see if the cache contains the variables that match the user.  This caching system would need to be shared between data centers because a variable that is saved from a web page would be lost if the user’s next request was directed to the other data center.  To get a rough idea of how big the multi-datacenter problem is, I would recommend browsing over this article: 

Distributed Algorithms in NoSQL Databases


The Developer Knowledge Dilemma

This is a really ugly problem.  Younger developers do not know the older languages and they are being taught techniques that require technologies that didn’t exist 10 years ago.  Unit testing is becoming an integral part of the development process.  Object oriented programming is used in almost all current languages.  This problem exposes the company to a shortage of programmers able to fix bugs and solve problems.  Bugs become more expensive to fix because only experienced programmers can fix them.  Hire a dozen interns to fix minor issues with your software?  Not going to happen.  Assign advanced programmers to fix bugs?  Epic waste of money and resources.  Contract the work to an outside company?  Same issues, expensive and difficult to find the expertise.


Conclusion

My take on all of this is that a company must have a plan for mitigating legacy code.  Otherwise the problem will grow until the product is too expensive to maintain or enhance.  Most companies don’t recognize the problem until it becomes a serious problem.  Then it’s somewhat late to correct and corrective measures become prohibitively expensive.  It’s important to take a step back and look at the whole picture.  Count the number of technologies in use.  Count the number of legacy web pages in production.  Get an idea of the scope of the problem.  I would recommend keeping track of these numbers and maybe compare the number of legacy pages to non-legacy pages.  Track your progress in solving this problem.

I suspect that most web-based software being built today will fall into the MVC-like pattern or use APIs.  This is the latest craze.  If developers don’t understand the reason they are building systems using these techniques, they will learn when the software grows too large for one data center or even too large for one web server.  Scaling and enhancing a system that is broken into smaller pieces is much easier and cheaper to do.

I wish everyone the best of luck in their battle with legacy code.  I suspect this battle will continue for years to come.

 

Webpage Source Code Layout

Summary

In this blog post I’m going to talk about the wrong and right way to layout your front side assets.  By this, I mean the html, js, images and css files.

Legacy Code

In the “good ole’ days” of legacy code such as ASP, and .Net using front-side and code-behind, many programmers would mix Javascript with HTML and CSS code.  Along came JQuery and the need to embed event handlers inside of HTML came to an end.  Yet, somehow the entire developer community didn’t get the memo on how much easier it is to provide full separation of Javascript and CSS from HTML.

Another method used in legacy applications is to print the HTML, Javascript and CSS from the code-behind.  Don’t do this!  Avoid this technique like the plague.  Visual Studio can keep track of JQuery functions and printing some functions and calling them from front-side code will cause warnings and errors (because Visual Studio can’t find the function that will only appear when the program is running).

What’s the Big Deal?

There are several reasons for separating Javascript from HTML and your code-behind code (i.e. C# or VB.Net).

1. It reduces confusion between languages.  The JQuery or Javascript is in the js file while the html is in the cshtml or aspx file.

2. Assets can be bundled.  MVC and the newer .Net websites can perform automatic bundling of js and css files.

3. Assets can be minified.  MVC and the newer .Net websites can perform automatic minification.  This will cause web pages to load faster.

4. You can upload your js and css files to a CDN for faster distribution, reducing the load on your web servers.

How to Convert Your Code

Many programmers prefer to generate their javascript because they can print code-behind variables in the output.  This can be handled using hidden input html tags.

Front-side HTML code:
<input type=’hidden’ id=’myVariable’ value='<%=variabledata %>’ />

Js file:
var myVariable = $(‘#myVariable’).val;

Or, if you’re using Razor, you can use the viewbag instead of the ugly “<% %>” tags.

Another method is to use a javascript section in your front-side code to set the variables in one block.  This will be done before you include your js files (inside the page header):

<script>
var myVariable = ‘<%=variabledata %>’;
var MyOtherVar = ‘<%=variabledata %>’;
</script>

This will not be minimized or bundled, but it is usually a small amount of javascript code.

Your next step is to remove all event handlers from HTML.  Make sure there are no “onclick” events or any other javascript in-line code.  Use JQuery handlers instead:

$(‘#idName‘).click(function(){
   // jquery function code here
});

This will eliminate a lot of clutter inside your HTML code.  You’ll need to make sure that your HTML has the proper id tags so you can attach event handlers to your code.

Remove all your in-line style codes.  Move these to a style sheet.  One of the benefits of containing all of your css in style sheets, is that you can use a css pre-processor like “less”.  Less is a language that can extend the power of css, making it more dynamic.  For more information about less go here.

You can also change your website theme by switching css files.  If you created a lot of in-line css, you’re stuck.  This code is embedded with your HTML and would need to be altered using variables (like color and background-color for example).  The css pages for each theme can be stored along with the images that match the theme.  Then the path names provided at the top of a web page can be setup as variables controlled by the code-behind or controller.


Content Delivery Networks

If your Javascript and css code is contained in their own files, you can upload these as static files into a CDN.  This will provide the end user with a lower latency time when they visit your website.  If you are dynamically generating your Javascript, then it will need to be transmitted from your web servers directly.  This puts a load on your web servers and it prevents you from using a CDN for this content.  To reduce the load on your web servers you would want to load all static files such as images, Javascript and css files onto the CDN (as well as any static HTML files).

When you use CDN’s you’ll need to pre-minify your JS and CSS files, instead of doing this automatically.  There are a lot of programs available that will minify these types of files and you can include this in your deployment process.






 

Creating a COM Object for Classic ASP

Summary

This blog post will show you how to create a COM (Component Object Model) object in C# that you can use in your classic ASP code.  Why would anybody do that?  Amazing as it might seem, there is a lot of classic ASP code out there in the form of legacy applications.  It’s monstrously difficulty to replace this code due to the fact that classic ASP isn’t compatible with anything and it doesn’t play nice with any other language.  So I’m going to show the basic mechanics of how to create a COM object in C# and how to incorporate it in your ASP code.

Writing Your First COM Program

First, let’s write the simplest program possible: Hello World.  I am going to follow a similar path as this article (which is where I learned some of this from):

Creating a COM object from scratch with C# 

There are a couple of changes I’m going to make because VS 2012 and above have a built-in GUID generator and I want to show how you can build something with no parameters, just to keep it ultra-simple.

Step 1 – Create your C# program

Create a new C# class library project.  You’ll need to add a using statement for the interop services library to the top of your code:

using System.Runtime.InteropServices;

Step 2: Construct the Class

For my example, I’m going to make this just a simple class with one method:

public class Launcher
{
    public string Hello()
    {
        return Hello world“;
    }
}

I’m leaving out the constructor, since it’s not used anyway.

Step 3: Presenting our Class Through an Interface

In order to access any methods or classes inside the COM module, we need to provide an interface.

public interface ILauncher
{
    string Hello();
}

You’ll also need to add the interface name as the base class for the Launcher object.


Step 4: Making the Connection

We need to add an attribute to our class to make sure it doesn’t automatically generate another interface (we want to use the interface we typed up manually):

[ClassInterface(ClassInterfaceType.None)]
public class Launcher : ILauncher
{
    public string Hello()
    {
        return Hello world“;
    }
}


Next, I’m going to deviate from the original article and allow early and late binding by adding the InterfaceIsDual attribute:

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ILauncher
{
    string Hello();
}

Step 5: Making them Unique

This is where I’m really going to deviate from the original article.  You’ll need to generate GUID’s for both the interface and the class. Now go to the “Tools” menu and select “Create GUID”:

Choose #5, and click on the “Copy” button.  Then paste it into your code:

[Guid(“6216B529-3E4A-4FE8-8F7A-BE99C33DB1F1“),
 InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ILauncher
{
    string Hello();
}

[Guid(41027763-2E19-415A-8525-F48F604EE810),
 ClassInterface(ClassInterfaceType.None)]
public class Launcher : ILauncher
{
    public string Hello()
    {
        return Hello world“;
    }
}


You might have to remove the square brackets to make the syntax correct (as shown above).


Step 6: Going Underground with Cryptography

This is where you’ll have to drag out the “sn” utility and give your assembly a strong name.  You’ll have to search your hard drive for the sn utility and there are probably more than one version.  I found mine at this path:

“C:Program Files (x86)Microsoft SDKsWindowsv8.1AbinNETFX 4.5.1 Toolssn”

I chose the latest version that was installed on my PC.  You’ll need to open a console window (go to your start menu and type “command” in the search box.  Then navigate to the project directory of your application.  Then execute the sn utility with the “-k key.snk” parameter:

“C:Program Files (x86)Microsoft SDKsWindowsv8.1AbinNETFX 4.5.1 Toolssn” -k key.snk

You’ll need to keep the path name quoted since it has spaces in it.  Once you execute this command there will be a file generated in your project directory named “key.snk”.  Now you need to add this file to your project as a link.  So right-click on your project and select “Add -> Existing Item”.  Don’t hit the “add” button, on the add button there is a down-arrow that allows you to select a different option:

Select “Add As Link”.  To use this file, we need to go to the project properties (right-click on your project and select “Properties”).  Then select the “Signing” tab.  Now click on the “Sign the assembly” check box and choose the “key.snk” file from the drop-down list:


Save your changes.


Step 7: Wrapping it All Up

Before building your solution we need to modify some settings.  In Deutschzuid’s article that I cited at the beginning of this blog post, you are directed to change your target build version at this point.  I’m going to leave it at “any” (the default).    Go back to your project properties and select the “Application” tab.  Click on the “Assembly Information” button.  Check the “Make Assembly COM-Visible” check box.

Now switch to the “Build” tab and check the “Register for COM interop” check box.


Step 8: Compiling it and Taking it for a Walk

Now you can build the solution.

First, let’s try this in ASP.  Make sure you have IIS installed and running on your PC.  Create a sub-directory in your C:inetpub directory named “aspcom”.  You can startup the IIS control panel (go to your start menu and type “iis” in the search box) and create a new application under your default website.  Name your application “aspcom” and point the directory to the new directory you just created.  You’ll need to click on “Edit permissions” and the directory properties window will pop-up.  Click on the “Security” tab.  Click “Edit” then “Add”, then type in “IUSR” and click “Check Names”.  Then click “OK”, then check the “allow full control” check box.  Then “OK”, 

Then repeat: “Edit”, “Add”, type “IIS_IUSRS” and click “Check Names”.  You might need to change your domain to the local PC domain for this to check right.  Then “OK”, then “allow full access”, then “OK” and last “OK” to close the properties window.

Now you’ll need to add those same two rights to the directory that contains your COM object project.  Just navigate to your project directory and right-click on it.  Then repeat the steps above to give full rights to “IUSR” and IIS_IUSRS”.

Restart IIS.

Now create a text file inside the C:inetpubaspcom directory named “home.asp” and type (or copy) this in:

<%
Dim MyComObject
Dim MyText

Set MyComObject = Server.CreateObject(“Launcher.Launcher”)

MyText = MyComObject.Hello()

%>
<html>
<head></head>
<body>
    <%=MyText %>
</body>
</html>

In the IIS control panel is a link called “browse” with a url on it.  You can click this link to get to the ASP directory, but you’ll have to add home.asp to the end of the path.  Then you should see “hello world” printed on your browser.

Next, create a text file on your desktop and name it “test.html”.  Now type or copy this into it:

<HTML>
<HEAD>
<SCRIPT language=”javascript”>
function Test() {
var objTest = new ActiveXObject(“Launcher.Launcher”);
alert(objTest.Hello());
}
</SCRIPT>
</HEAD>
<BODY>
<INPUT Type=”button” onClick=”Test()” Value=”Click here to test!”>
</BODY>
</HTML>


Now save it and double-click on the html file.  You’ll have to allow blocked content then click the button.  Then answer yes to the active-x control warning and you’ll see a text box displaying “hello world” in it.


Step 9: Deploying the dll on Another Machine

If you want to deploy the dll on another machine, you’ll have to add your dll to the registry by using the regasm utility.  First, copy your dll to the target machine (just the dll).  Then you need to find the regasm program on your pc, just like you did with the sn utility above.  Choose the latest version.  Navigate to your dll’s location and use this command:

regasm ComClassExample.dll /codebase /tlb /nologo

For testing purposes, you don’t need to use regasm.


Troubleshooting Tricks

OK, now there is an issue if you are attempting to change your COM program after you have executed it from an ASP program.  That issue is that IIS has the DLL locked and you can’t re-compile.  So you’ll need to reset your IIS before you re-build your application.  Then you can run your ASP program again.

Next, you are going to want to know what is going on while you are troubleshooting this project.  Especially if it doesn’t work the first time.  So in the IIS console, click on your application (aspcom), double-click on the ASP icon:


Expand your “Debugging Properties” section and change “Enable Client-side Debugging” to true and also change “Enable Server-side Debugging” to true.  Click on “apply”.  

Now, if something blows up, you can attach a debugger and see where it breaks in Visual Studio.  You can also get a good error message, like “permission denied”.

Don’t forget about the IIS log files.  They are located in the C:inetpublogs directory.  These are usually pretty cryptic, but sometimes they can shine some light on what’s wrong.

You can also open your home.asp page in Visual Studio and put a break-point on it.  Then choose “Debug -> Attach to Process…”, then select w3wp.exe and click the “attach” button.  Refresh the web page and the breakpoint should be hit.  You cannot get tool tip help in asp, but you can put a variable in your watch list and see what is contained in the variable.

One other annoying thing you might run into.  If you click the “Restart” button in the IIS control panel and your IIS does’t restart (it just sits there scanning, like it’s waiting for something) that means that there is a w3wp.exe process holding it up.  Just CTRL-ALT-Delete and start task manager.  Then find all w3wp.exe processes and “end process”.  You’ll notice that your IIS control panel will suddenly respond.


Download the Source

You can download the source code from my GitHub account by clicking here.