This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


This article assumes you're familiar with Visual Basic and ISAPI.
Download the code (4KB)

Porting Windows CGI Applications To ASP
Robin Ren
     
Although Active Server Pages are defining the new Web server specifications, thousands of CGI scripts are still creaking along. Converting your scripts to ASP can be well worth a bit of effort.
The Microsoft Internet Information Server 4.0 technology in Windows NT® Server is capturing a lot of attention these days for its flexibility, robustness, and great performance. So you would think the entire world, or at least the folks hosting their Web sites on Windows NT-based boxes would convert to IIS 4.0 overnight, right? Wrong! They already have a working Web site in which they have invested time and money. Unless there is a way to port the existing applications to the new paradigm without having to rewrite everything from scratch and retest apps, those people will not convert—at least not any time soon.
      There is a way to make the leap without too much hassle. CGI2ASP is a framework for porting programs written in Visual Basic® using one of the most popular old paradigm Web programming interfaces, Windows CGI (not actually part of Microsoft Windows, but an O'Reilly & Associates product), to component-based ASP applications with virtually no change to the existing Visual Basic®-based code.
      The basic function of a Web server is to take requests from and send responses to Web clients through the HTTP interface. Most of the Web pages on the Internet today are static HTML files sitting on the server's hard disk. All the server has to do is find the right file and send it to the client using HTTP. But more and more commercial Internet and company intranet sites are deploying sophisticated Web applications that rely on dynamic Web pages generated on the fly. To churn out these dynamic pages, the Web server usually needs either in-process or out-of-process help from other programs. These helper programs typically perform functions such as parsing user input and formatting output into HTML or something the client can understand. Sometimes helper programs need to perform more complicated tasks such as accessing back-end databases, applying business rules, and communicating with other servers.
      One of the most popular ways of generating dynamic Web pages in Windows is the Windows CGI programming interface, originally created by Robert Denny as part of the HTTPd Web server running on Windows 3.1. Now part of the O'Reilly catalog of products, Windows CGI is supported by several major Web server products on the Windows NT platform, including O'Reilly's Web Site (the successor to the HTTPd shareware program) and Netscape FastTrack and Enterprise Servers. Windows CGI gained its popularity because it uses Visual Basic. Armed with some basic HTML knowledge, a programmer using Visual Basic can be turned into a Windows CGI developer in days.

How Windows CGI Works
       Figure 1 shows the basic architecture of a Windows CGI application. The client request is first sent to the server over the Internet via HTTP. The server receives it, determines that a Windows CGI program needs to be run, and writes the information to an input file. Then the server launches the Windows CGI program, typically an out-of-process executable file. This program reads the input file, does the necessary processing, writes the output to an output file, and terminates itself. The Web server process, which has been waiting while the Windows CGI program was working, reads the output file and finally sends the output back to the client via HTTP.

Figure 1: Windows CGI Architecture
Figure 1: Windows CGI Architecture

      Several points are worth noting here. First, the Windows CGI programs are standalone, out-of-process, single-threaded executable files, usually written in Visual Basic. This kind of one-thread-per-process programming model can trace its origin to its CGI counterpart on the Unix platform, where processes, not threads, are the basic unit of execution. Under a multithreading operating system such as Windows NT, each process runs in its own memory space, and having many executable programs running on your Web server at the same time is inefficient.
      Second, the Web server and Windows CGI programs communicate with one another through input and output files. The input file uses the Windows INI file format. Microsoft provides special Win32® API calls to allow quick access to INI files. In the early days when there was no COM or DCOM, passing information back and forth using INI files was a great idea. The performance was remarkable since there was no better alternative. Visual Basic also has no concept of standard input/output pipes (stdio), so file-based I/O is just about the only way to feed it data. However, if you are running a popular site, your hard disk access speed can quickly become a serious bottleneck.
      Last but not least, the architecture of the Windows CGI interface demands that the Web server and Windows CGI programs run on the same computer. There is no easy way to distribute workload to other servers on the network. This means your Web site will not be very scalable as your company grows.

Windows CGI Framework
      As shown in Figure 1, the Windows CGI framework is an essential part of the interface that lies between the input/output files and the custom code. The framework has always been provided with the Windows CGI interface as a Visual Basic module, cgi32.bas. The following discussion is based on version 1.8 of this file. The latest version, as well as the Windows CGI specification, can be downloaded from http://website.oreilly.com.
      The Windows CGI framework takes care of many common routines for you, such as parsing the input file into key-value pairs, reading environmental variables, and writing to the output file. It provides your custom code with some 20 standard CGI environmental variables, including CGI_ QueryString and CGI_ RemoteHost, that are all defined as public string variables. The Windows CGI framework also provides your custom code with several public functions to communicate with the Web server. Figure 2 shows the three most commonly used functions: GetSmallField, FieldPresent, and Send.
      The CGI environmental variables and public functions together define an interface between the framework and your custom code. Only through this interface does Windows CGI custom code communicate with the Web server via the framework. The interface also forms a foundation upon which you can create a new framework with the exact same interface to repackage your custom code into components.
Figure 3: Project Win
Figure 3: Project Win
      When developing a Windows CGI application, you must write your custom code as one or several .bas modules, include the framework, cgi32.bas, into your Visual Basic project, and compile it into an executable file. Let's walk through a typical Windows CGI sample, which I'll port to component-based ASP pages later on.
      I've created a simplified Windows CGI intranet phone directory and reduced it to its simplest form. This sample retains some of the basic characteristics of Windows CGI applications. It uses environmental variables and the GetSmallField function to read the input and uses the Send function to write to the output. The sample app uses Data Access Objects (DAO) to access a back-end Jet database. The data-access capability is one major reason why most Windows CGI applications were developed in the first place. Like many other Windows CGI applications, this one controls its flow, or the order of different screens users see in their browsers, by sending different pages depending on whether the request method is GET or POST.
      The Visual Basic project window contains the two modules included in the project: the Windows CGI framework and the custom code module (see Figure 3). The project is compiled into an executable file, search.exe, and put into a Windows CGI-enabled folder on the Web server. The user points their browser to this EXE file to use the application.

Figure 5: User Input Form
Figure 5: User Input Form

       Figure 4 shows the code contained in the custom code module. The starting point of the custom code module is the CGI_Main sub procedure. CGI_Main first looks at the CGI_RequestMethod environmental variable. If the request method is GET (the first time the user requests this application), CGI_Main calls SendShortForm to display an online form (see Figure 5). The user fills out the form and submits the request to the same URL using the POST method. This time CGI_Main knows it is a POST request by reading CGI_ RequestMethod. It calls SendResponse to read from the back-end database and sends the result to the Web server, which relays it to the user, as shown in Figure 6.

Repackaging Your Code Into Components
      There is no direct way to port Windows CGI applications to Active Server Pages without rewriting a substantial portion of your program. There is an indirect way to reach this goal and achieve even better performance. You probably know that Visual Basic 5.0 or later can be used to create COM components, which in turn can be used by Active Server Pages. The key is to turn your existing Windows CGI applications into components first, then use these components in ASP pages.

Figure 6: Search Result Page
Figure 6: Search Result Page

      How do you turn your existing custom Visual Basic-based code into components? Repackage it! Remember when I discussed an interface between the Windows CGI framework and the custom code? This interface is composed of public CGI environmental variables and several functions, including GetSmallField and Send. You can replace the Windows CGI framework with a new CGI2ASP framework. This new framework will preserve the interface with your custom code, but it also knows how to communicate with ASP pages.
       Figure 7 shows the architecture of a Windows CGI- converted ASP application running under IIS 4.0. The ASP page communicates with the CGI2ASP component through a Request object and an output string variable. Request is an ASP built-in object, containing standard CGI environmental variables, user form inputs, and much more. Inside the CGI2ASP component, the new CGI2ASP framework is responsible for reading the input from the Request object and writing to the output string.
      It is easy to see why this component-based ASP architecture solution is superior to Windows CGI. First, you run the component in the same process as the Web server itself, which eliminates a lot of overhead associated with spawning and destroying a new process every time a user accesses a Windows CGI application. Furthermore, using the Request object and the output string variable is much more efficient than using the input and output files, since no disk access is required.
Figure 7: CGI2ASP Application Architecture
Figure 7: CGI2ASP Application Architecture

      In IIS 4.0, every application runs under the control of the Microsoft Transaction Server technology. MTS oversees the life cycle of each component. When a component is released by an application, it's not destroyed. Instead, MTS deactivates it, recycles it, and prepares it for just-in-time activation again. MTS also provides the flexibility of running certain applications in separate memory spaces, so if one application crashes, it will not bring down the whole Web server. Please note that even when an application runs in a separate memory space from the Web server, all the components of that application will still run in-process in that memory space while being monitored and recycled by MTS. This is very different from Windows CGI, where a process is created and then destroyed with every request to that application.
      MTS makes it possible to run components on other servers using DCOM. Therefore you can host a Web site on one server, and your ASP pages can activate and use components running on another server. This gives your Web site more flexibility and scalability.
      MTS also lets the components share expensive resources such as database connections more efficiently through resource pooling. You can expect to get a significant performance boost by repackaging your Windows CGI custom code, which connects to a Jet database, into components running under IIS 4.0 and MTS technologies.

The New CGI2ASP Framework
      The CGI2ASP framework is composed of two files: cgi2asp.bas and interface.cls (see Figure 8). The first file, cgi2asp.bas, provides your custom code modules with the same interface as the original Windows CGI framework. It provides most of the CGI environmental variables (the few missing ones are either unavailable or unnecessary under IIS), implements the GetSmallField, Send, and FieldPresent functions, and has a basic error handler. The code provided here does not implement every feature of the original cgi32.bas. If your existing custom code uses some of the other features in cgi32.bas, whether it is a global variable or a public function, you will need to add it to the cgi2asp.bas file.
      ASP and Windows CGI have different naming conventions for multiselection form input fields. Suppose you have a number of checkboxes named hobbies. In ASP, they are implemented as a collection that can be accessed individually as Request.Form("hobbies")(index). Under the Windows CGI specification, however, the first selection is named hobbies, the next one hobbies_1, and so on. The GetSmallField and FieldPresent functions shown in Figure 8 hide this difference from your custom code.
      The class module, interface.cls, is included because a Visual Basic component has to have a public interface through which the outside world (ASP pages in this case) can communicate with the component. It has only one public function or method: GetOutput, which takes a Request object as a parameter and returns a string.

Figure 9: Project Properties
Figure 9: Project Properties

      Let's go through the steps to port my sample intranet phone directory, a Windows CGI application, into component-based ASP pages.
      The first step is to open a new Visual Basic ActiveX DLL project. Make sure to use the Single Threaded threading model under Project Properties (see Figure 9). I'll explain why later. You may also need to add a reference to the Microsoft Active Server Pages Object Library in the Project References window.
      Next, add the CGI2ASP framework files, cgi2asp.bas and interface.cls, and your custom code modules (custom.bas here) to the project (see Figure 10).
Figure 10: Adding Files and Modules
Figure 10: Adding Files and Modules
      Then make any necessary cosmetic changes to your custom code. In custom.bas, the path to the application page was referred to as search.exe. It should be changed to search.asp. Since IIS automatically sends HTTP header information, you may want to comment out those Send statements relating to the HTTP header, otherwise the header information will be displayed in the client's browser window. Figure 11 shows the resulting custom.bas module. If you compare it to the original code shown in Figure 4, you'll notice that all the changes are cosmetic and easy to make.
      The next step is to compile the project into a DLL component. If the component will run on the same machine where it was created, Visual Basic automatically registers it. If it runs on a remote machine before the component is ready to use, you will have to register it using either the MTS explorer or a Visual Basic setup routine.
      The last building block of the application is an ASP page. In the sample, the ASP page does nothing other than create an instance of the component, pass the Request object to the component, get the result back, and relay it to the client. Here's the ASP page for the sample phone directory, search.asp:

 <%@ LANGUAGE="VBSCRIPT" %>
 
 <%
     Set objOutput =
         Server.CreateObject("prjDirectory.interface")
 
     Response.Write (objOutput.GetOutput(Request))
 
     Set objOutput = Nothing
 %>
      The user will notice no difference in the application after the paradigm shift, except that they need to point their browser to search.asp instead of search.exe. The search result will be identical to the one shown in Figure 6.

Debugging CGI2ASP Components
      Almost everyone who has developed Windows CGI applications has used the famous


 MsgBox("I am at Line # XX")
statement to quickly isolate a problem when something doesn't work. Unfortunately, this trick no longer works when you try to debug the newly converted components. If you are porting existing applications, try to finish all your debugging in the Windows CGI environment before you try to migrate them. If you are developing a new application, you should not be using this CGI2ASP method at all—go straight to ASP.
      If you really have to debug your CGI2ASP application, you can do it using the standard Visual Basic-based method of debugging components, which is to write a small client and step through the execution inside the Visual Basic environment.
      As I mentioned before, once a component is loaded into IIS, it stays loaded so it can be reused. This creates a problem if you need to make any changes to the component but do not want to stop and restart the Web service. Fortunately, with IIS 4.0 it is possible to unload an application along with all its components if the application is running in a separate memory space. The rule of thumb is that when you are developing and testing a new application, it makes sense to run it in a separate memory space from the server process. Once the application is fully debugged, you can decide whether to run it in the same process as the Web server.

More Performance and Scalability
      Notice that all the CGI environmental variables in Figure 8 are defined as public variables. Anyone familiar with component development knows that having public or global variables is a bad thing! Global variables severely limit the scalability of a component by giving it a by-user internal state, so multiple users have to run multiple instances of the component instead of sharing one. Thus you have to make the Visual Basic project single-threaded, since you do not want multiple instances of the same component to share those public CGI environmental variables. For a busy site, running tens or hundreds of instances of a component can be a real performance drag.
      Defining the environmental variables as public is a necessary compromise to avoid substantial change to the existing custom Visual Basic code. In fact, you can use all local variables if you let the CGI_Main procedure in custom.bas take some parameters. Then you can use the apartment threading model for your component. I'll leave this exercise to those who are concerned about the performance and scalability of their Web applications.

Conclusion
      With a clear understanding of both the architectures of Windows CGI and CGI2ASP plus some careful tuning, you can port Windows CGI applications to component- based ASP applications that have more flexibility, better scalability, and increased performance. I hope you'll take advantage of the newer, better Internet technologies. No application migration will be successful without careful planning, precise execution, and testing, testing, testing. This one is no exception.

From the October 1998 issue of Microsoft Interactive Developer.