SOME CODE REVIEW RECOMMENDATIONS FOR COM+ VB Developers

By Peter A. Bromberg, Ph.D.

Peter Bromberg  

 


I've developed a reputation for constructive ideas and criticism around our developer group at work, and recently as part of an overall effort to help optimize our "collective code", I had the chance to uphold that reputation a bit by distributing some code review comments to key members of our group. I had been reviewing some of the component source code, as well as some of the professional documentation regarding COM+, and I'd like to share a few of the suggestions I made for improving the performance and scalability of some the components we had been working on:

1) First, and most important, is that if you are writing Component Services - compliant COM components that will be hosted in COM+ Applications, you should use ObjectControl_Activate and ….Deactivate instead of Class_Initialize and Terminate in all classes. This holds true whether or not the component initializes or is enlisted in transactions.

The Class_Initialize event happens before the object is put under COM+ activity control. This can have undesirable consequences that can make components difficult to debug. When an object is created to run in COM+ there is an internal structure called context for it that encapsulates info such as transaction enlistment, threading model and so on. When the Class_Initialize event runs, the context has not yet been associated with the object.



We do this by adding Implements ObjectControl at the top of the class module. Move all code (if possible) from Class_Initialize to ObjectControl_Activate, and from Class_Terminate to ObjectControl_Deactivate.

I have built a small demo COM+ component along with a VB executable "Test harness" to illustrate the method, as well as to pop up some messageboxes on the firing of each of the above-captioned events so that you can get a feel for how these events are carried out when a class method is invoked under COM+. Compile the DLL portion of the project group and drop the DLL into a COM+ Application. Then, run the Test Harness VB executable which is marked as the Start Up project in the project group. You'll find this code in the download zip linked at the bottom of this article.

2) Early binding should be used wherever possible.

If your code has instances of   "Dim XYX as OBJECT", that's late binding. It's important to note that this has nothing to do with the operator used to instantiate the object (e.g., CreateInstance, CreateObject or New). In all cases, early binding requires you to have the correct references set in the VB Project. The reason why we want to do this is that late-bound calls are done through the IDispatch interface, which requires two calls to execute a specific method.


3). Declare Parameters as ByVal whenever possible. Above all other transgressions, this is the most common blooper I have found.   VB defines parameters by Reference by default. By using the ByVal keyword when declaring a parameter, the parameter doesn't get transmitted back to the caller using the network unnecessarily. Also, if the client does not require the data to be sent back, passing in the parameter as ByVal matches the interface's semantics more closely. In other words, except for specific instances where a function is supposed to actually MODIFY THE VALUE of a variable that is passed in as a parameter (rather than returning a RESULT based on what the method does), we should be passing parameters specifically coded as "ByVal".


4). Do not declare variables "AS NEW".

Declaring variables using "as new xyz" causes every reference to be slower, and can also have an unpredictable effect on the object lifetime. In addition, when used in combination with private classes, it can bring unexpected thread behavior. Using "as new" causes VB to compile the component with extra checks to see if the object has been set to Nothing. If not, VB will create a new object EVERY TIME the variable is used!

Objects should be declared and created in distinct steps.   It is important to use the correct operator to create objects:

Use New:

To create utility objects or objects such as ADO, MSXML, MSMQ.
To create custom objects in other project or DLL

Use CreateObject:

To create custom objects in the same DLL
To create objects by a runtime-specified ProgID and / or computer.

Examples of correct usage:

Set oXMLDom=CreateObject("MSXML2.DOMDocument.3.0")
Set oTransfer = New OtherProject.CTransfer
Set oConn = New ADODB.Connection

Creating an object in the same DLL (COM+):

Set oISPSubs = CreateObject("MyProject.MyClass")

5) State Management

Tthe ASP Session object is a big convenience, but it's also a real drag on performance. I've written a state management component "SessMgr" that works with SQL Server. It is very fast, has been fully stress-tested and is 100% UNICODE compliant. It's syntax is virtually identical to the intrinsic ASP Session object. Either this, or some similar component should be used, and ASP Session state can be TURNED OFF on IIS, thereby speeding up web server(s) and reducing the load on the IIS machine(s). On a web farm, this is not a luxury, its a necessity. Session State is best stored in SQL Server, even if you decide to cache it somewhere else later.

I hope these few suggestions have either presented some logical new information, or have helped to "jog your memory" about things you already knew you should do.

Download the code that accompanies this article

Peter Bromberg is an independent consultant specializing in distributed .NET solutionsa Senior Programmer /Analyst at in Orlando and a co-developer of the NullSkull.com developer website. He can be reached at info@eggheadcafe.com