Accessing COM/COM+ Objects Within the ASP.NET Environmentby Shelley Powers
If you've had a chance to review even a small part of the documentation that comes with Microsoft's new .NET initiative, you're aware of how different ASP.NET is from the original ASP server environment. Visual Basic programmers are still recovering from the fact that the Variant data type no longer exists and that C# is now the default language for ASP scripting blocks.
Still, as imposing as all the differences are, you'll find that you can make your migration to .NET, generally, and ASP.NET, specifically, without having to re-code and recreate everything you've ever done. In fact, you can use your existing ASP COM/COM+ components from within your new or newly modified ASP.NET pages without having to edit or recompile these objects.
Because I've just written a book on ASP components within the Windows 2000/COM+ environment (Developing ASP Components, 2nd Edition), I decided to take a look to see how the existing ASP COM/COM+ components are going to fit into the new .NET initiative when it does finally release as a production environment (most likely sometime in 2001).
First, though, let's take an existing ASP page and move it from ASP to ASP.NET.
Moving from ASP to ASP.NET
The most important fact to know about ASP.NET is that it can exist side by side with ASP on the same IIS server. In fact, they can coexist within the same directory if you wish. This means that you can start the move to ASP.NET while still providing support for your existing ASP applications. So, take a deep breath--you have plenty of time to make the move to .NET.
What will happen to your pages in the new ASP.NET environment? Well, I grabbed one of the example ASP pages from my book and migrated it over to ASP.NET just to see what would happen to it--after first installing support for .NET on my Windows 2000 Professional machine, of course. (You can download the first public beta of Visual Studio.NET.)
Since none of the book's pages are incorporating .NET functionality, such as Web Services and Forms, each ASP page is converted to a basic ASP.NET page simply by renaming the file from .asp to .aspx. I tried this migration with Chapter 7's ("Creating a Simple Visual Basic ASP Components") asp0701.asp sample file [downloadable examples also available from Examples on oreilly.com], which contains the following VBScript:
<% Dim obj Set obj = Server.CreateObject("asp0701.First") Dim msg msg = obj.sayHello("World!") Response.Write "<h3>" & msg & "</h3>" Set obj = Nothing %>
The component accessed in the script is a Visual Basic 6.0 component that just appends the word "Hello" to the name passed to the component method, and returns the whole as a string; a twist on the traditional "Hello, World" first program. Once I accessed the renamed file from my browser, I knew that the .NET environment setup was correct as I received a .NET compiler error, as shown in Figure 1. (Always look for the positive in any event.)
The error occurred because of the use of the Set keyword when accessing the VB component--Set and Get are not supported for object instantiation in the .NET environment.
Well, hey, this is a simple fix. I like simple fixes.
I pulled the use of Set from the example and tried again. However, the second time accessing the page still didn't succeed. The reason for the second failure was that the argument list for the Response.Write method requires parentheses--all method calls are surrounded by parentheses in .NET.
Well, hey, another simple fix; I can learn to like this type of migration. Once this change was made, the example worked and "Hello World!" displayed in the browser.
What's interesting to note about this basic exercise is that during this process, I had not only migrated my ASP page to ASP.NET, but I also implicitly migrated my COM+ component to the new .NET environment. ASP.NET still supports the late-binding technique of CreateObject.
I was happy about the ease of moving my component and ASP page to ASP.NET, but I wondered if this approach provided for optimum performance of my ASP/ASP.NET application. Wouldn't it be better to integrate my component more fully into the ASP.NET environment and perhaps take advantage of performance improvements such as early binding? Time to take a closer look at accessing COM/COM+ components within ASP.NET applications.
The Longer View
The most significant change between the world of Visual Studio 6.0/COM+ and Visual Studio.NET is managed versus unmanaged code. In a nutshell (hmm, that word sounds familiar), managed code is any code that runs with the support of the .NET Common Language Runtime Services. These services provide support for memory management, cross-language exception handling, and so on.
COM+ components aren't based on managed code. However, as we've seen, you can access components from within ASP.NET applications. You can access the components, as is, using CreateObject, or you can create a .NET compatible "wrapper" for your component through a helpful little utility called TlbImp (part of the .NET Framework SDK). The only requirement is that your component must have an associated type library, as asp0701.dll does.
The TlbImp utility will create a .NET compatible assembly that exposes your COM object for access to any .NET managed code, whether contained within an ASP.NET application or not. If you have a separate Type library file, with a .tlb extension, you can run the utility, as follows, and a DLL of the same name as the type library will be generated:
If your type library is compiled as part of the component DLL itself, such as it would be with the Visual Basic COM+ asp0701 component, you'll specify a new name for the assembly using the "out" argument:
tlbimp asp0701 /out:asp0701lib
You must specify the out parameter because tlbimp won't let you overwrite the existing DLL object.
Using TlbImp with the existing asp0701.dll generates a new file, asp0701lib.dll. Now, we're ready to try this NET-able wrapper within a ASP.NET page.
Trying Out the New Assembly Wrapper
ASP.NET assemblies need to be moved to a /BIN directory located off of the main application directory. Once moved, the .NET compiler can locate the assembly by its location. The original COM/COM+ component must also be registered within the system--using .NET won't get you out of this requirement. Use the system utility regsvr32 to register the component or register it using the COM Services manager (part of the Administrative tools for Windows 2000).
Once the assembly file has been moved and the component registered, you can access it within the ASP.NET page. In the following example code (modified from the original asp0701.asp page), the first line of the file is a directive to import the new assembly into the application. This import lists the namespace for the component, in this case "asp0701". Now, instead of using the CreateObject late-binding technique, you can create the object using the "New" keyword and incorporate early binding into the ASP.NET application:
<%@ Page Language="VB" %> <%@ Import Namespace="asp0701" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> <HTML> <HEAD> <TITLE>Developing ASP Components</TITLE> </HEAD> <BODY> <% Dim obj As First obj = new First() Dim msg As String msg = obj.sayHello("World!") Response.Write("<h3>" & msg & "</h3>") %> </BODY> </HTML>
(The namespace and the assembly name can differ. Remember, with .NET and COM/COM+ objects, the namespace is the first part of the PROGID of the component, as in asp0701 for asp0701.First.)
The result of accessing this ASP.NET page is the same "Hello World!" message printed out to the browser. Except now, the unmanaged code contained in the component is "wrapped" within a .NET context.
Before I leave this topic, let's take a look at what happens with the COM/COM+ component during this whole process.
NETifying COM/COM+ Components
When you run TlbImp on a COM/COM+ component, the utility strips out references to IUnknown and IDispatch methods, and converts the "old" interface to a nice new managed one. (See the documentation on NET for details on managed versus unmanaged code--a topic way beyond the scope of this article.) Yes, just when you finally got the hang of IUnknown, it gets pulled.
In addition, type definitions are imported as basic types.
To see the contents of the imported assembly file, there's another .NET utility, Ildasm, that you can use to see the generated assembly transformation:
Figure 2 shows the Ildasm output for the assembly for asp0701.dll.
Notice in the figure that the COM/COM+ String data type has now been transferred to the .NET System.String data type.
From ASP to ASP.NET in a couple of steps. Not bad considering the massive changes between the two environments.
To migrate to ASP.NET, you don't have to make an all or nothing decision--you can move your existing ASP applications to the new environment in a controlled, gradual manner. And, as you've seen from this article, you can continue to use your COM/COM+ components as is in this new environment without having to modify or recompile these components.
Best of all, you can continue with your existing component development and know that your components will move to .NET when you're ready to move to .NET.
O'Reilly & Associates will soon release (March 2001) Developing ASP Components, 2nd Edition.
Sample Chapter 10, Server-Side XML Through VB ASP Components, is available free online.
For more information, or to order the book, click here.