Sometimes we are tempted to believe that .NET is a cure for all of our development
problems and that every technique used in the pre .NET days should be sent to
the recycle bin this moment. A technique which suffers greatly from this misunderstanding
is ActiveX, also known as (OLE) automation or COM. The CreateObject function
creates COM objects and is often used in classical ASP server side scripts to
customize Web pages. It has not always led to the best coding practices, but
it worked. The ASP.NET server side controls and the truly object oriented .NET
Framework are a huge step forward. A lot of problems COM used to solve are now
better in .NET, but that does not mean that COM no longer exists. Some of your
existing COM classes work very well, why should you convert them to .NET? That's
not what COM promised you! Relax, there are still a lot of things you can do
with COM in ASP.NET. In this article I will show you some of the great COM support
it has to offer.
COM's Not Dead!
Before we dive into the .NET support I want to take a closer look at COM itself.
COM stands for the Component Object Model which describes a protocol to separate
the interface of an object from its implementation. The interface is what the
object looks like, it is the declaration of the properties and methods. The
implementation is the code which actually runs when a method is called or a
property is read. The user of an object uses COM to get a description of the
class and a way to construct an object of the class. The user will get a COM
interface to the object. All methods and properties can be executed on this
interface, but the COM object cannot be destroyed by the user The COM object
will be kind of garbage collected. All of this is not uncommon, interfaces are
widely supported in .NET. Describing classes is something .NET is very good
at and every assembly has its metadata. COM uses typelibraries to describe classes,
they are quite often available as a resource inside the library file itself.
Windows supports a variety of COM-interface types, the most commonly used is
the Idispatch interface. A COM class implementing this interface exposes its
functionality in two ways:
- Its methods can be called directly from the vtable of the object, the layout
of this vtable is described in the typelibrary of the COM class. A compiler
will map calls to the vtable. This is called vtable binding, these days it
is called early binding as well. (Actually early binding refers to dispinterfaces,
whose scope is limited to COM events).
- The interface has methods which accept the name of the method or property
in string format, perform a run-time lookup in the typelibrary after which
the method can be invoked. A script interpreter will use these methods to
map script calls to object methods. This is called late binding.
Classical ASP scripts use the second technique to populate Web pages on the
server. Client side scripts use late binding to run code in the browser on the
client. Objects which are addressed using these Idispatch interfaces are often
called (OLE) automation objects. The term ActiveX was once coined for all COM
functionality but these days it is mainly used to describe visual (ActiveX-)
controls which are addressed using a whole bunch of different COM interfaces.
COM is a great protocol for connecting software components created with different
tools, it is supported by all major Windows languages like VB(A), Delphi, C++,
VBscript and JavaScript and last but not least .NET. In the .NET Framework class
libraries you will find the System.runtime.interop namespace. The majority of
the methods and properties in there deal with Unmanaged COM interoperability
which involves the creation of COM objects as well as passing data to and from
these objects. COM objects do not operate in the type safe .NET managed environment.
Communication between the managed and the unmanaged world is quite a job. The
passing of data is known as marshalling, .NET will use the system marshaller
of .NET itself to implement the marshalling of COM objects. Sometimes you hear
people say that parts of the kernel of .NET are implemented using COM. I would
say that COM and .NET use the same techniques to get objects connected.
Let's start working with COM in an ASP.NET application. I have built a very
simple automation server. It is named DemoServer.MyDemo
and has one method, named MyMethod, taking one
string type parameter and returning this string prefixed with "your server echoes
". It was built using Delphi, for more information how to do this you are invited
to www.Gekko-Software.nl/Software.htm.
A Client Side Automation Object
In an ASP.NET application all code runs on the (IIS-) server. Code running
on the client can do very specific things like inspecting a specific hardware
device or the surfer's address book and report to the server part of the application.
When implemented as an automation server, its objects can be created and manipulated
by just a small piece of script on the page being browsed. Because I am not
very good with html, I prefer to implement all this in C# code-behind on a Web
page.
I will experiment with a simple Web page. This page has two TextBoxes and a
Button. These controls are all server side controls which means that they are
not available on the client in the same way as they are on the server. The TextBoxes
will have a client control representation in the form of text input controls.
My script can read and set their text values and the server will see these in
the postback. The first TextBox is used to enter a string which will be passed
to the automation object, the second TextBox will hold the result of a function
call on the object. I will write a Jscript function which will create the automation
object, read the TextBox, call a method and update the second TextBox.
function doMySubMit() {
var MyAx;
MyAx = new ActiveXObject("DemoServer.MyDemo");
document.getElementById('TextBox2').value = MyAx.MyMethod(document.getElementById('TextBox1').value);
} |
ActiveXobject is the Jscript function which creates a new automation (ActiveX)
object as identified by the ProgId parameter. On the resulting object I fire
MyMethod passing it the string in TextBox1.
The result is written to TextBox2.
In C# constants have to be stored in classes, just like everything else. I
will create a static class to hold the script source and the related constants:
class MyJScript {
const string head = "<script language=\"JavaScript\">";
const string foot = "</script>";
public const string scriptBlockName = "startup";
public const string functionName = "doMySubMit()";
public const string MySubmit =
head
+
"function
" + functionName + "{" +
"var
MyAx;" +
"MyAx
= new ActiveXObject(\"DemoServer.MyDemo\");" +
"document.getElementById('TextBox2').value
= MyAx.MyMethod(document.getElementById('TextBox1').value);" +
"}"
+
foot;
}
|
A static class can be used without creating an object instance. After declaration
I can use MyJscript.MySubmit, a constant which
contains the JavaScript source wrapped up in script tags.
In the Page_Load event I have the opportunity to tailor the page to my needs.
Besides setting the controls I can inject client side script here. Page.RegisterStartupScript
injects a a script block in the page. Before doing so, Page.IsStartupScriptRegistered
will check if the scriptblock had already been added to the page to prevent
double work. Page.RegisterOnSubmitStatement
is an even more powerful method, here I can define the name of a client-side
script function (from my freshly inserted script block) which will fire when
the form is submitted to the server. The MyJScript
class provides all parameters needed for these methods.
private void Page_Load(object
sender, System.EventArgs e)
{
if (! IsStartupScriptRegistered(MyJScript.scriptBlockName))
RegisterStartupScript(MyJScript.scriptBlockName, MyJScript.MySubmit);
RegisterOnSubmitStatement("Mysubmit", MyJScript.functionName);
} |
When the page is submitted my Jscript function will run on the client and its
result can be checked by inspecting the submitted TextBox2. Internet Explorer
will notice that there is something potentially very dangerous going on. The
automation object could house any code which could redistribute the client's
address book or even format its disks. When its security settings are not set
too low, IE will pop up a warning dialog.

To prevent this dialog from appearing you could either change the safety setting
or sign your ActiveX class. The first option should not be taken too serious.
For the second one you will end up with a company like Verisign to buy a certificate
with which you can sign your automation class as being trustworthy. Signing
is a snap in .NET, but for classical automation classes it takes more time and
money.
A Server Side Automation Object
In classical ASP most scripts run on the server. Automation objects used in
these scripts are useful to pass (part of) the work to a software component
which is built with a better suited and more reliable tool. In scripts everything
is late bound, a lot of errors will not be noticed until the script is actually
executed. Besides that compiled code does run faster than interpreted code.
With ASP.NET this "scripting hell" can be sent to the recycle bin
and a lot of the automation objects which just generated html code can be discarded
as well. Then all that remains are the automation classes which still do something
useful. One option is to rebuild them in .NET and the other is to use them as
they are. The marvelous support for automation in .NET makes the latter a snap.
In the solution explorer I will add a reference to the COM library I want to
use. After clicking "Add Reference" in the solution explorer I pick
the COM tab and select the DemoServer library. Now Visual Studio will import
the typelibrary and generate a wrapper class for the DemoServer automation class.
My project now has a namespace interop.DemoServer which houses MyDemoClass
which implements the ImyDemo interface which
has a method MyMethod.

I can use the automation class like any other .NET class. Clicking Button2
creates the automation object and calls its method.
private void Button2_Click(object
sender, System.EventArgs e)
{
DemoServer.MyDemoClass axo = new
DemoServer.MyDemoClass();
Label1.Text = axo.MyMethod(TextBox1.Text);
} |
That's all. All code runs, early bound, on the server in the code-behind of
the Web page. I have all server-side stuff available, including the server-side
version of the controls, I no longer need a TextBox to assign the result to,
a label will do.
In ASP.NET you can keep using your automation objects thanks to .NET Interop
which makes the using of automation objects inside .NET code seamless. Running
an object on the client is actually just the same as in pre-ASP.NET days. The
client is not aware that it is running .NET, it just runs a script. ASP.NET
provides very nice functionality to install client side scripts.