Creating a Server Component with VB - Redesigned - Part 1
By Doug Dean
Rating: 4.6 out of 5
email this article to a colleague
Overview
This article is for ASP developers and Visual Basic (VB) programmers who want to combine both technologies to write compiled VB components for ASP pages. When I reread my initial article, "Creating a Server Component with Visual Basic" (see http://www.15seconds.com/Issue/980930.htm), it struck me that a lot of code has flowed under the bridge since then. I also realized that the way I code a server-side component has dramatically changed from the method described in the previous article. I decided that writing an "upgrade" article was not only important for demonstrating a more manageable way to code server-side components in VB, but also because secure and fast processing components will continue to have an important place with Microsoft's Internet Information Services (IIS) for a long time to come.
I will summarize what a server-side component is as a short review before explaining how the component described here differs from the one described in the previous article
Download supporting source code
Brief Summary of What an IIS Server-Side Component Is and Is Not
Server-side components differ from client-side components by virtue of . . . well, which side they are on. A server-side component is a DLL file registered on the server computer that serves data to any visiting browser. Alternatively, a client-side component is registered on the visitors' computer where the browser is running. With Microsoft's Internet Explorer (IE), these client-side components are called ActiveX plug-in browser components.
ActiveX client-side components can be written in VB and sent, via the Internet or intranet, to an IE browser to produce wonderful results. The problem is that ActiveX client-side components are limited to IE browsers. On the other hand, or side, a server-side component written in VB can produce pure HTML code that will successfully render on any popular browser. The only limitation on the server-side is that the component has to be run on Windows IIS or a server compatible with the IIS application program interface (API). Thus, on the server-side, you can call the shots as far as compatibility, whereas on the client-side you're guaranteed compatibility only if you have a controlled intranet that ensures that IE will be exclusively used by all users.
IIS server-side components reside within the same memory space as IIS and readily wait for a call from any ASP page being processed on the server. Although you could inject any type of text/code into the ASP file sent back to a visiting browser, generally speaking, most server-side components are used to process time-consuming calculations and/or database information that's sent back to the visiting client browser as simple HTML code. The main point is that you can generate dynamically created text, or HTML code, from a server-side VB component that will work with any modern browser.
Design/Redesign Issues
The Downside and Upside to Server-Side Component Design
My initial article described how to include the ASP Object within a server-side VB component so as to capture variables set by a browsers' HTML form, a URL query string, session objects, etc. This made server-side component coding convenient since all the ASP objects, and their settings related to each individual visiting browser, were made available to the VB code as global-like variables.
But there was also a downside to this type of server-side component design. I found that managing the many aspects of the ASP Object from within my components became increasingly complicated as my projects grew. I also found that using property procedures did not add to the management or scalability of my components (property procedures weren't explicitly covered in the previous article so I'll briefly discuss them below).
So the components written in the way described in the previous article had the advantages of having access to all the many variable values provided by the ASP Object, as well as those that could be sent from an ASP file by setting the components' property properties in the manner illustrated below:
ASP file code:
<%
AspVariable = "a string example variable sent to the component"
Set ObjReference = Server.CreateObject("ProjectName.ClassName")
ObjReference. ExamplePropertyProcedure = AspVariable
ObjReference.ClassMethod
%>
Below is the VB code for the property procedure that will assign the value of the AspVariable variable from the ASP code above to the VB component variable named strPropertyProcedure.
VB Code:
Private strPropertyProcedure As String
Public Property Let ExamplePropertyProcedure(ByVal RHS As String)
strPropertyProcedure = RHS
End Property
Along with the ASP Object variable values and the components' property procedures, component variables could include values received from databases. So variables used within the previously described VB component had values coming from databases, property procedures, and the numerous inlets provided by the ASP Object.
Not only does a VB component that uses the ASP Object allow access for variable values going IN to the VB code, but the ASP Response Object can be used to return text or HTML from the VB code back OUT to the ASP file that called it. And the ASP Response.Write() method can be called multiple times from anywhere within the VB code.
Previous Design:
To summarize, a VB component designed like the one in the previous article will have access to all the variable values coming IN to it via the ASP Object, via property procedures, and via database table fields. It would send variable values OUT to the ASP page via the ASP Object.
Again, the downside to this design was keeping up with the many avenues that a variable could take when being sent in and out of the component. These design complications were increasingly detrimental as a project inevitably grew beyond manageable proportions, not to mention the scalability issues related to the overhead from using property procedures and the ASP Object within the VB code.
The solution was to forgo instantiating the ASP Object in the component and eliminating property procedures altogether. The newly designed server-side component reduced the complexity of the previous design to a simple set of classes that contained groups of various similar functioning methods that worked without access to variable values that could be mutually shared. The question was "what was the cleanest way to get variable values to the VB code in from the ASP file and back out from the VB component to the ASP file?"
Using Method Parameters and the Return Value
Avoiding using the ASP Object and property procedures simplified the component's design. It also limited the way variable values came in to the VB component to method parameters and database table values. Method parameters are the variables (parameter1 and parameter2 in the example code below) that are listed within parenthesis after a method's name:
MethodName(parameter1, parameter2)
This streamlined the component's processing, but placed the burden of variable access primarily onto the method's parameter list. Note that this list can grow increasingly large as a project matures. Since increasing the number of method parameters can become its own management problem, using database tables for certain types of values can help limit the number of method parameters needed. This design also lends itself to writing smaller methods.
Not using the ASP Object within the component also limited getting values out from the VB component to the method's return value. A method's return value is the value assigned to a single variable (strReturnedValue in the example code below) when a VB function method is called from the ASP code.
strReturnedValue = ObjectName.MethodName(Parameter1, Paramenter2).
The upside of this design is a simplified component that manages values coming in to the VB code via method parameters and database tables. It sends HTML code (or other value types) out to the ASP page as a singular method return value.
Current Design:
Changes Imposed by the New Design
Any variable values that the ASP Object previously provided to the VB code internally can now be externally assigned to method parameters from within the ASP file. These values are then sent to the component when it's called from the ASP page. Thus, this design places the management of ASP Object variable values in the ASP page.
One of the biggest changes that results from this design is with the VB methods that intermingled database information and HTML code. Since the ASP Response Object is no longer available from anywhere within the VB method, sending back data can't occur at random places within the VB code. I'm not religious about not mixing tiers when processing speed and security is more costly than presentation management. Sometimes the choice amounts to mixing tiers in one location or the other. Populating a HTML table with database field values from within VB code is sometimes preferable to merely sending a recordset back to the ASP file. HTML tag values used within the component can optionally be stored in database tables where the HTML presentation code can be managed separately.
The previous design allowed HTML and database values to be sent back in piecemeal fashion via the Response.Write() method from anywhere in the VB code. This sometimes took the form of looping through a database recordset, interspersing HTML TABLE tags, and then sending both back for every database record iteration. The new design requires the HTML code to be sent back as one string, all at once. This means putting concatenated database field values and HTML tags into a string during a recordset loop and sending the string value back at the end of the method, rather than in little spurts from various places within the method.
Since VB concatenation processing is costly, you can use string buffering whenever looping through a recordset while concatenating HTML tags to format database information. This article's example code will use simple, nonoptimized VB concatenation and no database example code (part two of this article will cover that topic). See the article "How To Utilize String Buffering within A VB Component" at http://www.dougdean.com to optimize your concatenation code if scalability is a concern.
Another important change was not using the component to summons up various ASP pages from within the VB code itself. Many different self-contained ASP pages could be generated from within a single VB component and managed via query-string values, as described in the previous article. The new design merely exposes the component's methods without managing a site's page flow from within the VB component code. The control of which ASP page to call after a VB function is completed is now placed back onto the ASP files rather than from within the VB code. This provides more flexibility and manageability.
You'll also find that in the component development phase IIS doesn't need to be installed on your system. You can send the VB component's return value to the VB Immediate window where it can then be pasted into a HTML editor as a preliminary test for those methods that generate HTML. Overall, this simplified component design can clear up many management problems with little cost to you in coding inconveniences.
You can see working examples of these two different designs by downloading some of my components that used the initial design (EZsite Forum 3, EZsite Calendar, and EZsite WebNotes) and comparing them with those using the more recent design (EZsite Forum DEV and EZsite Daily Planner). Working trial copies of all these components can be freely downloaded at http://www.dougdean.com.
A Conceptual Overview
The Anatomy of a VB Component
Since this article's intent is to present the basic concepts of writing a VB component of the design described above, the example project will remain simple and to the point. We'll cover the process of writing the VB code in a step-by-step. But first we'll do a conceptual overview of the anatomy of a VB component and it's relation to the ASP code it's called by.
When using VB to write a server-side component, there are three hierarchical names (used in both VB and the ASP file) to take note of:
Project name
Class name
Method name
The name used for a VB project is called (no surprise here) the Project name. Many developers refer to the Project name as the component name, but VB refers to it as the project. Our example's project name will be ExampleProject, although you can make up any name you want for your personal projects. You'll enter the Project name in VB by filling in a text field in one of the many VB property windows (all this will be explained in detail later). The Class name will be ExampleClass, which also be entered in a VB property window, and the Method name will be ExampleMethod, which will be entered directly as VB code.
Again, the three names used for our example component are:
ExampleProject as the project name
ExampleClass as the class name
ExampleMethod as the method name
To make things more interesting, the project name (component name) can also be used to refer to the DLL file that is produced by VB after the component's code is compiled. It will be the DLL file that contains the compiled VB code that will be used by IIS to serve up text or HTML directly to a visiting browser.
The method name refers to the sections of VB code that manage specific code functionality, like calculating a date or displaying a list of all the authors in a database. Component methods function like little black boxes that do some particular type of work and/or return specific information depending on what data you send it. There can be, and usually are, more than one method in a component. To manage the bulk of a component's methods in a more organized way, the methods can be grouped according to similar classifications of functionality. This is where the component classes come into play.
A component's class produces a copy of the class code in memory, now called an object, when you use ASP code to create the object. This is called instantiation, e.g., creating an instance of the class code for the ASP code's use. Once you have an object reference to an instance of the component's class code, you can use the methods contained in that class from the ASP code. Logically grouping your methods in various classes can add to the clarity of your component's design and make using the component's classes more intuitive.
Our example project, class, and method names will be used in the ASP file to instantiate the VB component, send values to the VB code from the ASP code as method parameters, and receive a value back to the ASP code from the VB method.
Calling the VB Component from an ASP File
The ASP file we'll use to host our VB component will use an object variable to hold a reference to the VB object code. An object can be created in an ASP file by using the CreateObject() method of the ASP Server Object, which returns a reference to the object it creates. We'll use objReference as our component's object variable in the example ASP file. The line of code below shows the ASP code needed to instantiate a VB component by using our component's project and class names (ExampleProject and ExampleClass). Notice that the object variable that will hold the reference to an instance of our VB component's class code needs to be preceded with "Set."
ASP code to instantiate a VB component:
Set objReference = Server.CreateObject("ExampleProject.ExampleClass")
Our VB component will accept three variable values sent to it from the ASP code and then send back one value to the ASP code, which we'll store in an ASP variable named strMethodReturn. The line of ASP code below demonstrates how the ASP code will acquire the value returned by the VB method. The object variable holding the object reference to the VB class code (objReference, set in the above line of ASP code) is used, along with the component's method name (ExampleMethod) to call the method's code. The example VB code below sends the VB method code three parameters values named Param1, Param2, and Parma3.
strMethodReturn = objReference.ExampleMethod(Param1, Param2, Param3)
Notice that the objReference.ExampleMethod part of the code above reflects our component's project, class, and method hierarchy. This occurs because the objReference object variable was created using the project and class names (ExampleProject.ExampleClass) via the CreateObject() method call. Since objReference virtually represents ExampleProject.ExampleClass, the top line in the example code below is conceptually the same as the line of code below it, which reflects our VB component hierarchy.
objReference.ExampleMethod
ExampleProject.ExampleClass.ExampleMethod
The (Param1, Param2, Param3) will have to match our VB component's method definition or signature, e.g., the number and type of parameter variables used when creating the VB method.
Here's two example lines of ASP code that instantiates a VB component's class and calls the class method to receive back a return value.
Set objReference = Server.CreateObject("ExampleProject.ExampleClass")
strMethodReturn = objReference.ExampleMethod(Param1, Param2, Param3)
To summarize the ASP/VB code conceptual landscape, the graphic below visually demonstrates how the example code in our ASP file matches up with the VB component's project, class, and method names. You can use this graphic image as a reference when you go through the step-by-step process of building the example VB component and ASP file. Each of the terms used in the diagram are briefly defined in the section that immediately follows the graphic. The various names used in the code of the diagram, and their relationships to one another, will also be covered in detail in the section of this article entitled "A Step-By-Step Guide for Writing a VB6 Component."
ExampleProject:
This is the name we'll give our example project (which can be considered the DLL file created when we compile our project's code). It's also know as a component. The project name can be entered in the Project Property window of VB.
ExampleClass:
This is the name we'll give our example class. A class can be thought of as a group of methods, along with any class-level data, which are organized by some functionality determined by the programmer. The class name can be entered in VB's Class Property window.
ExampleMethod:
This is the name we'll give our example method. Methods are the sections of code also referred to as " functions" in VB when a value is returned to the calling code. Methods are referred to as "Subs" when no value is returned.
Param1, Param2, Param3:
These are the names we'll give to the three variables that are sent from the example ASP file to the example VB code via the method's parameter list. The VB component programmer determines the parameter variable types, the number of parameter variables used, and whether they are optionally sent or required. Parameter variables that are optionally sent have some restrictions (see Optional below). The parameter variable names used in the ASP code don't have to match the parameter variable names used in the VB method code. Just the number of variables and their data type needs to match.
Server.CreateObject():
This is the ASP Object (server) and its method (CreateObject) used to create an object instance of our component. The CreateObject() method returns a reference to our object in memory so it can be used to call our component's class methods.
objReference:
This is the variable, determined by the programmer, that's used to hold an object instance of our component's class, e.g., a memory reference to an individual instance of the class (ExampleClass) of our project (ExampleProject).
Public:
This VB method modifier determines that this function can be called from code inside, as well as outside, of the component. ("Private" and "Friend" can also be used for other types of access/nonaccess to the method.)
Function:
This indicates that the method will return a value back to the code that called it. Use 'Sub' if no value needs to be returned to the code calling the method.
ByVal:
This indicates that the parameter variable value will be sent to the VB method code rather than a reference (ByRef) to the value. Use ByVal for calling methods from ASP files.
Optional:
Each parameter variable the programmer uses in creating the VB method must be used when the method is called, with the exception of those parameter variables set as optional. The restriction is that once a parameter is defined as optional, all the parameters following it must also be set as optional. Also, the code that calls the method must send values for all optional parameters preceding the last optional value sent (e.g., once you omit sending an optional parameter variable, you must omit all the optional parameter variables following it).
= False:
An "optional" parameter value can be set to a default value that will be used if a value is not sent to the method from the calling code. This way, if the calling code doesn't send a value for an optional parameter variable, you can determine what value will be used in your VB component code. Your default value will not be the one used when the calling code sends a value for this parameter variable. The value sent will be used instead.
String, Integer, Boolean:
This is the variable type you want the parameter variables to have. It saves memory and debugging time to set a parameter variable's type rather than using the variant type, which is the default type if you don't set them yourself. You can use any valid VB variable type here.
(...) As String:
This is the type of value returned from the VB method to the code that called the method in the first place. It's only used for functions, not Subs.
A Step-By-Step Guide for Writing a VB6 Component
What Our VB Method Does
Our simple example VB component will take the name and the age of a user and then return a string stating the user's age in number of days. There will also be an optional setting that can indicate which users are at least 45 years old, just in case they have forgotten.
So if we send a fictional name (unrelated to any known idol of mine) to our component as the value of the method's first parameter, say Eric Clapton, and an arbitrary age like56 as the value of the second parameter, we'll get the following results returned as a string:
Eric Clapton is over 20440 days old.
If we set the optional third parameter to True, which emphasizes who is 45 or older, we'll get the following string retuned from our method:
Eric Clapton is over 20440 days OLD.
Notice that our simple example method is, well, simple. It doesn't actually calculate how many days a person has been alive, it just returns how many days their age in years equals.
Since there are three different variables being used -- the user's name, the user's age, and whether to indicate that they are 45 or older -- we'll need three method parameters to carry this information from the ASP file to the VB code. When working with VB methods it's important to take into consideration what type of data you're working with. Here we'll use a string for the user's name variable that will be named "strName." An integer will be used for the age variable, named "intAge." A Boolean type will be used for the optional middle- age indicator, named "blnAgeEmphasisOn."
Three method parameters (variables to be sent to the VB component's method code)
strName (String)
intAge (Integer)
blnAgeEmphasisOn (Boolean)
Of course, it's not the name that determines a variable's type, so we'll need to declare the type of each of the method parameters as we define our method. But first we need to start up VB in a way that will produce as a server-side component for us.
Starting A Server-Side Component Project in VB
When you start up VB you'll see the New Project window. Select the New tab if it's not already selected. If you don't see the New Project window when VB starts up, select File/New Project from the menu at the top of VB. The New Project window will have various icons displayed. Select the ActiveX DLL icon by double-clicking it.
Once VB loads a new ActiveX DLL project you'll see at least two open windows: the Project window and the Properties window. If either of these two windows are not displayed you can display either of them by selecting View from the VB menu (View/Project Explorer and View/Properties Window).
Since VB inserts default names for the initial project (Project1) and class (Class1), we'll change these to ExampleProject and ExampleClass. If it's not already selected, select the default project name in the Project window, typically Project1. Now select the default project name (Project1) in the Properties window, delete it, and enter ExampleProject in its place. The name in the Project window will simultaneously change to ExampleProject as you type it into the Properties window.
To the left of the newly entered project name in the Project window there will be a small box with either a plus [+] or a minus [-] in it. If yours has a plus in it, select the [+] box so that it displays a minus. Now the default class name (Class1) will be displayed beneath the project name. Select this default class name in the Project window and change the default class name to ExampleClass in the Properties window.
Now let's save our project (File/Save Project) using the names VB suggests for the class (ExampleClass.cls) and the project (ExampleProject.vbp). You'll be asked whether these names are acceptable as VB displays two windows, one after the other. VB will save the code that comprises your class in a file with a CLS extension (although there's really no telling class code to save at this point). The project file has a VBP file extension where various settings, file names, and file locations of your project are saved. Be sure to save your project and class files in a directory that makes sense to you.
Now there's nothing left to do except to enter our VB method code. But first let's take a look at some of the property values for a server-side DLL component.
Server-Side Property Values
While you're in the Properties window with the ExampleClass properties being displayed, take note that the Instancing property is set to "5 MultiUse." This property value will change if you switch your project's type to a standard EXE project, so make sure it's set to "5 MultiUse" before you compile a project if you have fooled around with the type setting of your project in the Project Properties window.
Speaking of the Project Properties window, if you go to the VB menu and select "Project/ExampleProject Properties..." it will be displayed. Under the General tab selection of the "ExampleProject - Project Propertied" window, you'll notice that the Threading Model at the bottom right-hand side is set to Apartment Threading. This will ensure that more than one visitor will be able to use individual instances of our component class at the same time. Also, select the 'Unattended Execution' and 'Retain in Memory' options to avoid a memory leak bug in VB6.
The VB Method Code
Now we need to use the Code window in VB to enter our method code. If you don't have a window opened that has two drop-down boxes (typically showing General and Declarations, at least initially), then select View/Code from the VB menu. If your Code window is totally blank, type in the following code, which will require all variables to be declared.
Option Explicit
The way a method is defined is sometimes called its "signature." This includes whether the method is a Sub or a function, the method's scope (where it can successfully be called from), what type of variable the method returns if it's a function, the number and type of parameters, whether the parameter variables are passed by value or reference, whether the parameter variables are optional or not, and if the optional parameters have default values set for them or not.
Public Function ExampleMethod(ByVal strName As String, _
ByVal intAge As Integer, _
Optional ByVal blnAgeEmphasisOn As Boolean = False) As String
In the example code above, notice we've designed our method to be a public function. This means that any code outside of the component can successfully call this method because it's designated as "public." The method will also return a value back to the code that calls it because it's a function and not a Sub (Subs don't have return values). You can use "private" in place of public if you don't want code outside of the class to be able to call the method. Using "friend" will let other classes in your project call your method, but not any code outside of your project.
Since this is a function, we'll want to determine what type of value is sent back to the calling code. In our example, we'll be sending back a string so "As String" is attached to the end of the method definition. If no variable type is declared at the end of a method, it will return a variant.
Here's what we have described in detail so far...
Public Function ExampleMethod() As String
This is a valid method and if you type this line of code into the Code window, VB will accept it. As a courtesy to programmers everywhere, VB will even add a few spaces and place an "End Function" statement beneath the method definition in order to close off this function's code section for us.
Our VB method is designed with three parameter variables that will be assigned values sent from our ASP file code. The last of these three parameter variables will be optional, meaning its value can be validly sent or not sent. All method parameter variables used to receive values from code outside of the VB method itself need to be placed and declared between the VB method's parenthesis (). The variables that we declare as method parameters in this way can be used in the methods code just as if they were declared within the body of the method itself. The only difference is that the outside ASP code will be determining their values.
So rather than declare our three variables within the body of our method, we'll declare them in the methods definition, e.g., between the parentheses. Here are the three variables and their declared types:
strName As String
intAge As Integer
blnAgeEmphasis As Boolean
Now we'll designate the last parameter variable as optional:
strName As String
intAge As Integer
Optional blnAgeEmphasis As Boolean
Each parameter variable that's not designated as optional must have a value sent to it by the calling code or an error will be thrown. There's a restriction to using optional parameter variables, however. Once a parameter is defined as optional within the method, then all the parameters following it must also be set as optional. (See definition of Optional, above.) An optional parameter value can be set to a default value that will be used if a value is not sent to the method. If the calling code doesn't send a value for the optional parameter variable, you can determine the value that will be used in your VB component code without the need to set it in the method's body. The default value will not be the value used when the calling code sends a value for the parameter variable. The value sent will be used instead. So, in our example we'll set the optional blnAgeEmphasis Boolean variable to false. As a result, if the calling code doesn't send a value for it, we won't offend anyone by emphasizing the fact that they are age 45 or older, by default at least.
strName As String
intAge As Integer
Optional blnAgeEmphasis As Boolean = False
Now we need to designate each parameter variable as being passed to the method code as ByVal. This indicates that a copy of the variable's value will be sent from the calling code to the VB method code rather than a reference (ByRef) to the variable's value (which remains resident in the memory of the code that called the method). Use ByVal for calling methods from ASP files.
ByVal strName As String
ByVal intAge As Integer
Optional ByVal blnAgeEmphasisOn As Boolean = False
Next, we need to add a few comas, spaces, and underline characters (, _) to the end of some of the code lines so we can break up our lines for appearance sake without VB protesting that the syntax is wrong. When we place our parameter list in the method's parenthesis, we get the following error-free method definition:
Public Function ExampleMethod(ByVal strName As String, _
ByVal intAge As Integer, _
Optional ByVal blnAgeEmphasisOn As Boolean = False) As String
Typing our method definition into the VB code window will generate an End Function. Everything in between the method's definition we typed in and the End Function line is called the body of the method. This is where the code for revealing the day count of a person's age in years will be placed.
The first code we'll add to our method's body is a declaration of a string variable that will be used to store the string value this method will return. We could manage to send back our reply text without using a string variable to gather this information, but using a string for this purpose makes for cleaner code most of the time.
Dim strReturnString As String
Now we can begin to construct our return string. We'll first use the strName variable value sent by the ASP code via the method's parameter list. We'll concatenate the strName parameter variable value with the string literal (" is over "). Added to this will be our calculated "age in days," using the intAge parameter variable, also from the incoming parameter list. The intAge will be used to calculate the number of days a person has lived, depending on their age in years. Notice that since we're using the product of two integers (intAge * 365) we'll change the resulting integer of our calculation into a string before we concatenate it to the strReturnString string. The VB Cstr() method is used to do this.
strReturnString = strName & " is over " & CStr(intAge * 365)
Given that the name value sent to us from the ASP code was "Eric Clapton" and the age sent was 56, our strReturnString should now contain the following value:
Eric Clapton is over 20440
To finish off our string we'll either add " days old." or " days OLD.", depending whether the value of intAge is 45 or greater and whether the blnAgeEmphasisOn variable is set to true.
If blnAgeEmphasisOn And intAge > 44 Then
strReturnString = strReturnString & " days OLD."
Else
strReturnString = strReturnString & " days old."
End If
If a value for blnAgeEmphasisOn was not sent as a method parameter from the ASP code, its value will default to "false" as determined by our method definition. If it's set to "true" by the calling ASP code and the intAge variable value is 45 or greater, we'll get the following string to return:
Eric Clapton is over 20440 days OLD.
Otherwise we'll get:
Eric Clapton is over 20440 days old.
To return the string to the calling ASP code we assign the value of our string to the name of our method:
ExampleMethod = strReturnString
The complete method code follows:
Public Function ExampleMethod(ByVal strName As String, _
ByVal intAge As Integer, _
Optional ByVal blnAgeEmphasisOn As Boolean = False) As String
'///// Set local string variable
Dim strReturnString As String
'///// Set the value of the returning string
strReturnString = strName & " is over " & CStr(intAge * 365)
'///// Add to the strReturnString
If blnAgeEmphasisOn And intAge > 44 Then
strReturnString = strReturnString & " days OLD."
Else
strReturnString = strReturnString & " days old."
End If
'///// Send back composed string
ExampleMethod = strReturnString
End Function
Using a VB Component from an ASP File
Instantiating the VB Object in ASP Code
Much of the ASP code we now need was previously introduced in the 'A Conceptual Overview' section of this article (see above). The basic sequence of steps follows:
To instantiate our VB component by using the CreateObject() method of the ASP Server object.
Call our component's method using the proper method parameter variables.
Assign the string value returned from our VB method to a variable in the ASP code.
Then use this variable in a Response.Write() method to send it on its way to the visiting browser. We'll instantiate our VB component's class with some code in the ASP file that will host our VB component. Here's how our VB component is instantiated.
Set objReference = Server.CreateObject("ExampleProject.ExampleClass")
The ASP CreateObject() method returns a reference to an object of our VB code so that we can call any of public methods for our class from the ASP file. Notice that it's our VB project and class names that are used as method parameters of the ASP CreateObject() method. The objReference variable is used to hold the reference to the object instance of our component's class (e.g., a reference to the memory location of an individual instance our VB class code).
Using Our Components' Method from an ASP File
We can now use our component's class method, ExampleMethod, and receive a string indicating the minimum number of days a person has lived. The line of code below uses literals as parameter values and assigns the string value returned from the method to a variable named strMethodReturn.
strMethodReturn = objReference.ExampleMethod("Eric Clapton", 56, True)
Note that the objReference represents the ExampleProject.ExampleClass used in the CreateObject() method when our component was instantiated. Recall that you can think of the objReference.ExampleMethod part of this code as equivalent to ExampleProject.ExampleClass.ExampleMethod(), our component's hierarchy, although it can't be literally used like this.
Alternatively, you can use variables instead of literals for the method's parameters. The parameter variable names you choose in the ASP file don't have to be the same variable names used in the VB method parameter list. They just need to match as far as the number of nonoptional parameters, the order in which they are used, and the variable types used in the VB parameter list.
aspName = "Eric Clapton"
aspAge = 56
aspEmphasis = True
strMethodReturn = objReference.ExampleMethod(aspName, aspAge, aspEmphasis)
Using variables in place of literals tends to be cleaner and more manageable, especially when your method's parameter list becomes lengthy.
Now we just need to use the strMethodReturn variable within an ASP Response.Write() method to send our returning method value back to the browser that visited our example ASP file. Here's the entire ASP code. We'll add a line of code to de-reference our component's object at the end of the code for the purpose of cleaning up.
<%
'///// Instantiate the component object
Set objReference = Server.CreateObject("ExampleProject.ExampleClass")
'///// Set local variables to send as method parameter values
aspName = "Eric Clapton"
aspAge = 56
aspEmphasis = True
'///// Call the component's method and store the returned string
strMethodReturn = objReference.ExampleMethod(aspName, aspAge, aspEmphasis)
'///// Send the returned string to the visiting browser
Response.Write(strMethodReturn)
'///// Clean up
Set objReference = Nothing
%>
Putting the above ASP code within an ASP file will result in the following string being placed wherever the Response.Write(strMethodReturn) line is used with our example parameter values.
Eric Clapton is over 20440 days OLD.
Getting the DLL to Work from the ASP File
Testing our component is a matter of letting Windows know where to find it when it's called from the ASP file. First, save your work and then select the VB Run icon or Run/Start from the VB menu. VB will temporarily register the component so that the system will know where to look for it. While VB is running the component use Personal Web Server (PWS) or IIS to visit the ASP file that instantiates the component. Note that you can't just use a browser to "load" in the ASP file as a HTML file. The ASP file must be sent through the server for the ASP code to be operable, just like any other ASP file.
The browser should display "Eric Clapton is over 20440 days OLD."
To allow our component to work on another server, the component has to be compiled into a DLL file and then registered on the server's computer. This also applies to the computer on which you developed the component if you want to use the component without having it run from VB. The only file you'll need for your component to run on different computers is your DLL file, as long as the computers in question have the VB runtime files installed. The VB 6 runtime files can be downloaded at ftp://ftp.microsoft.com/softlib/mslfiles/VBRUN60SP3.EXE for those systems that don't have VB6 installed.
To compile the component into a DLL, select "File/Make ExampleProject.dll" from the VB menu. A dialog window will allow you to save a DLL file named ExampleProject.dll to any directory. After selecting an appropriate directory, clicking OK will begin the compiling process and produce a DLL file.
To manually register the DLL on the computer you're going to use it on, you'll need to use the Windows regsvr32.exe utility program. Find the regsvr32.exe program on your computer [typically in the C;\WINNT\System32, C:\WINDOWS\SYSTEM, or C:\WINDOWS\SYSTEM\inetsrv directories]. Select your computer's Start button and choose Run from the menu. Within the Run window type:
[path]/regsvr32.exe[path]/ExampleProject.dll
The [path] portion of this statement represents your computer's particular directory paths to the regsvr32.exe and the ExampleProject.dll files. Then select OK and your component should be ready to work like it did when it was running from VB. If you get an error message during the registration process, read it carefully. It will probably say that the directory path you typed is erroneous.
Well, that's basically it. As a by-product of writing your IIS server-side components with this design, you can call your methods from other VB components as well as from ASP files. This permits further modulation and more flexibility.
Tips for Your VB Components
Viewing the Method Results without Leaving VB
A good way to write VB methods without compiling and testing for every change or new development is to capture your VB method's return value from within VB itself.
Load the example component code from this article into VB and go to the VB menu, select "Project/ ExampleProject Properties..." and then use the "Project Type:" drop-down list at the upper left-hand side of the Project Properties window to select "Standard EXE" as the new project type. The following warning will appear within a window.
---------------
Current Public/Instancing/DataSourceBehavior/Persistable property values are not valid in this type of project ("ExampleProject"). The property values have been changed
---------------
Select OK, knowing that you'll have to change some of the settings back to what they were as a DLL project.
Now select "Project/Add Forum" from the VB window and choose the Form icon by double-clicking it. Then double click on your project's newly created form, and place the following code in the form's code window.
Private Sub Form_Click()
Dim objReference As New ExampleProject.ExampleClass
Debug.Print objReference.ExampleMethod("Eric Clapton", 56, True)
End Sub
You can now run your VB program with the "Immediate Window" open to see the results of your method (View/Immediate Window from the VB menu) by clicking on the form. If you're sending back any HTML tags from your method, you can copy and paste the results from the Immediate Window and view it from any HTML editor or your browser.
Once you complete testing your code in this manner, be sure to set the Instancing back to "5 - Multiuse" in the Project Properties window.
Returning HTML Code -- Making UI Your Component's Business
With design issues, decisions have to be made about balancing programming resources. Shifting flexibility, processing load, memory usage, interface code, and other programming realities between various code areas incorporates tradeoffs that should be approached pragmatically rather than 100% religiously, in my opinion at least.
Having said that, I'm always torn when working with populating a HTML table with values returned from a database within a component. A recordset could be returned to the calling ASP file where the HTML TABLE tags can be used while looping through the recordset. Alternatively, the HTML TABLE tags can be used in the VB component, where I prefer to use recordsets. Although assigning HTML tag values to variables in the ASP file and sending them to a VB component via method parameters can gain flexibility, this can be cumbersome when using many HTML tags.
I have settled on using method parameters for those variables that need immediate, or frequent, changes and storing HTML tag data in database tables. The VB code can provide one or more default settings for the HTML tag values used within the method. Alternatively the VB code permits changes to be made to the HTML tag values by using the HTML values stored in a database table when the default values are not chosen.
I use a method parameter to indicate when the default HTML tag values are not wanted. The parameter variable is typically of Type Integer and named something to the effect of "intTableProperties." If presentation HTML changes are needed, setting this parameter to a number greater than zero will cause the method to load in alternative HTML tag values from a database table instead of using the default values within the method code. The intTableProperties is then used as the ID key for various tables populated with different HTML values. This also allows an ASP page to change its HTML on-the-fly with preset designs stored in the database just by assigning a different value to a method parameter (intTableProperties).
Avoiding Concatenation Slowdowns
For any large amount of concatenation work within a VB component I recommend using string buffering. This is a fancy way of doing your own concatenation by adding strings to a buffer rather than using VB's own concatenation process. The problem comes from the fact that VB can't estimate the amount of memory that may be needed to construct the string you want to return from the method. Since you have a better idea of the length of your return string, you can better determine the size, and resizing, of a string buffer to hold the values created by a looping recordset.
You can read more about this in an article entitled "How To Utilize String Buffering Within A VB Component" at http://www.dougdean.com/How2Project4.htm.