One of the biggest challenges Web administrators face today with n-tier Web applications is managing those applications and their components. When you use a COM component (e.g., a DLL) in a Web application, you must address special considerations, such as:
- What happens when a developer needs to publish a component?
- How do you roll out a new version of one component to multiple servers at the same time?
- How do you automate the process of creating Microsoft Transaction Server (MTS) packages or COM+ applications on the server?
MTS and COM+ both let you automate their operations programmatically. The MTS automation interface lets you create installation and management applications for the MTS environment. You can build a custom setup application almost as easily as you can with the Microsoft Visual Basic (VB) Setup Wizard. You can access the automation functions from within Active Server Pages (ASP) as well.
You can combine VB with the MTS and COM+ automation features to automate many of the management tasks you face. For example, if you combine automation with VB and .bat or .cmd scripts, you'll have a powerful and robust server-management tool. In this article, I show you how to manage MTS applications programmatically.
Automating MTS Functions
MTS provides a set of scriptable objects that you can use to create installation and management applications. Almost all the activities you can perform within MTS Explorer are available to you when you use these objects. To demonstrate how you can use some of these objects, I created a simple program called MTSPackageLister.vbp. This program shows you a list of all MTS packages on the current system and lets you refresh the list on demand without restarting the program. MTSPackageLister.vbp also lets you create a new package and add its description. The program is simple, but it demonstrates how you can use these objects to assist in managing your servers and applications.
The MTS Administration objects are broken down into two parts: general catalog interfaces and utility interfaces. General catalog interfaces let you connect to systems and enumerate MTS object groups. Utility interfaces provide the nuts and bolts to create, modify, and remove packages, components, interfaces, and roles.
The MTS Catalog Object
The MTS catalog is the MTS data store that maintains configuration information for components, packages, and roles. When you use MTS Explorer to interact with components and packages, you're interacting with the MTS catalog behind the scenes. Just as you access the catalog information through MTS Explorer, you can access it by creating an instance of the Catalog object and invoking its methods.
The Catalog object represents an object within the catalog that includes such items as a package, a component, an interface, or a role. A Catalog collection is a collection of related objects within the catalog. The RelatedCollectionInfo collection contains the available collections of any given Catalog object. A number of collections are available within the Catalog object. For example, the Main catalog includes these collections:
These collections provide access to other entries in the catalog. You can use the collections to programmatically navigate through computers, packages, components, and so forth.
The first step in using MTS objects is to create a reference to them in your VB application. Open VB, and create a new Standard EXE project. From the Project menu, choose References; add a reference to the MTS 2.0 Admin Type Library. (This step is already completed in the sample application.) Now, let's dive into MTSPackageLister.vbp. This application consists of the Main subroutine, the FindPackage function, the GetAllPackages function, and the AddPackage function.
The Main Subroutine
The first line in the Main subroutine in Listing 1 instantiates the Catalog object:
Set catalog = CreateObject _ ("MTSAdmin.Catalog.1")
At this point, you've connected to the catalog on the server running the MTS utility. You can also remotely connect to other servers with the Catalog object's Connect method. (To use this utility on a server or remotely connect to another server, you must run it under the proper security context. If you run the program and your account doesn't have proper permissions, you can't access the MTS catalog.) For example, you can use this method to connect to the MTS catalog on the server named Server1:
You can pass in a null parameter ("") to connect to the server running the application. (The sample code doesn't use the Connect method; as a result, all actions work on the machine running the utility.) The next line in Main executes the CatalogCollection object's GetCollection method to generate the Packages collection:
Set packages = catalog _ .GetCollection("Packages")
The FindPackage Function
The second chunk of code in Listing 1 isn't used in MTSPackageLister.vbp. The FindPackage function takes a package name as a parameter and searches the Packages collection for that package. The steps are straightforward. First, you populate the Packages collection:
Next, the For...Next loop increments through the collection until the current package name matches the package name passed into the function. When the match occurs, the If...Then...Else statement passes back the package's ID as the return value to FindPackage, as callout A in Listing 1 shows.
The GetAllPackages Function
Now that you have the Packages collection, you can use it for several tasks. First, the GetAllPackages function retrieves a list of packages and places the list in an array. The first action in the function executes the Populate method to retrieve the packages from MTS:
You must use the Populate method to retrieve the packages even though you used the GetCollection method to generate the collection earlier. Next, set the variable n equal to the number of packages in the collection:
n = packages.Count
The code loops through the packages and extracts each package name:
PackageName = packages.Item(i) _ .Name
The ListPackages function in Listing 2 executes GetAllPackages, then takes the array the function returned and loads the items from it into the list box on the MTSUTilInferface form that Listing 2 shows. You can click List Packages, which Figure 1 shows, at any time to refresh the list of packages. For example, let's say you add a new package to MTS while you have MTSPackageLister.vbp open. Clicking List Packages will execute the GetAllPackages function, which in turn repopulates the collection and picks up the new package.
The AddPackage Function
One of the most frequently performed tasks is adding a package to a server, which you usually do by starting MTS Explorer, drilling down to the Packages Installed folder, and adding the package. (If you want to add a description for the package, you must add it on the package's Properties dialog box.) MTSPackageLister.vbp also includes code that lets you create a new package. In Figure 1, you can see the two text boxes at the top of the form labeled Package Name and Package Description. If you enter a name in the Package Name text box, the program will display the Add Package button that Figure 2, page 9, shows. Clicking this button adds the new package and refreshes the package list.
Look at the AddPackage function in Listing 1. This function takes a package name and description as parameters. The first line adds a new package to the Packages collection and sets the newPack variable to reference the new package:
Set newPack = packages.Add
Next, the function sets the name of the package to the incoming name and the description to the incoming description:
newPack.Value("Name") = _ sPackageName
newPack.Value("Description") = _ sPackageDescription
Finally, and most important, the function calls the SaveChanges method:
lNumChanges = packages _ .SaveChanges
The last line of the function sets the return value of AddPackage to the return value of the SaveChanges method:
AddPackage = lNumChanges
If the add is successful, the return value is 1.
An ID is necessary when you want to work with an existing package or to perform functions with a newly created package.
The MTS Utility Interfaces
MTS's Utility interfaces let you perform more specific tasks on particular collections within the catalog. Three MTS Utility interfaces are of particular interest: the ComponentUtil object, the RemoteComponentUtil object, and the PackageUtil object.
You can use the ComponentUtil object to install and import components into a package. For example, you can automate the process of adding components to a new package. The first step in working with a package is to obtain its ID. This ID is the same one that either FindPackage or a new package returns by accessing the Key property:
newPackID = newPack.Key
Next, call the GetCollection method to obtain the ComponentsInPackage collection:
Set componentsInNewPack = _ packages.GetCollection _ ("ComponentsInPackage", _ newPackID)
You can obtain a pointer to the UtilInferface by calling the GetUtilInterface method:
Set util = componentsInNewPack _ .GetUtilInterface
Finally, you can install your component by executing the InstallComponent method:
util.InstallComponent _ "d:\Components\Customer.dll" _ , "", ""
You can use the RemoteComponentUtil object for performing the same activities on a remote component (e.g., a component that you access through Distributed COM—DCOM—on another computer).
The PackageUtil object interacts with the MTS catalog to install, export, and shut down packages. The ability to shut down components automatically is powerful—it lets you create a Web interface to manage packages from anywhere on the LAN or Internet. Your developers also need to know about this feature so they can shut down packages on demand without using MTS Explorer. (MTS Explorer runs only in Microsoft Management Console—MMC. You can build a simple Web page that is easier to use and has features MTS doesn't, such as the ability to shut down an MTS application on a group of servers with one click.)
When you want to move a package from one system to another or create an installation that lets a client access an MTS package, you generally export the package. From MTS Explorer, you just right-click the package name and select Export. Using MTS Administration objects, you can access the Utility interface of the Packages collection and call its ExportPackage method, passing in the ID of the package to export.
This code passes the ID of the new package you just created to the ExportPackage method:
Dim packUtil as object Set packUtil = packages _ .GetUtilInterface packUtil.ExportPackage _ (newPack.Id, "c:\" & _ newPack.Name, 0)
The ExportPackage method takes three parameters. The first parameter is the package ID, the second is the full pathname for the exported package, and the last parameter sets the export options. If the third parameter is 0, then the method exports no users. If you set the parameter to MtsExportUsers, then the method exports users with roles in this package.
You've seen how you can create a simple application that lets you list packages on a server and add a new package to that server. The other code snippets also demonstrate how you can add components and perform other related tasks.
Let's look at a typical example in which these utilities can really help. Suppose you have 15 Web servers, all of them running IIS and MTS. Let's say those servers are running the same configuration of MTS packages and components. What happens when you need to roll out new versions of the components to the servers?
You can easily take the code in this article and feed it from a file or database. For example, if you have five components that you want to load into the same package on each server, you can put the component definitions in Figure 3 into a text file. An application can easily pick up this information from the file, determine that all these components go into the CustomerService package, then magically perform all the work. That's where this management interface really comes into play: It lets you automate many mundane tasks you perform over and over.
This article has shown you how to automate retrieving information about a package and how to automate creating packages. As I mentioned earlier, you can also use the interface to add components to a package by calling the InstallComponent method of the GetUtilInterface interface.
The Microsoft Transaction Server Programmers Guide on the Microsoft Developer Network (MSDN) has a wealth of information about using this automation interface to developing utilities. You can access the MSDN MTS index page at http://msdn .microsoft.com/library/psdk/mts20sp1/ gettingstarted_7msw.htm. The Microsoft article "HOWTO: Add Users and Groups to MTS Roles Programmatically" (http://support.microsoft.com/ support/kb/articles/q241/3/45.asp) is also useful.