Microsoft Transaction Server Helps You Write Scalable, Distributed Internet Apps

Dave Reed, Tracey Trewin, Mai-lan Tomsen

Dave Reed (product unit manager), Tracey Trewin (program manager), and Mai-lan Tomsen (programming writer) are part of the MTS product team at Microsoft.

Talk to anyone build­ing a multiuser enterprise server application and they will tell you about all sorts of interesting problems they solved that had nothing to do with the actual business logic. Complex problems relating to thread management, security authorization, and transaction support across multiple databases might come up. This article explains how Microsoft® Transaction Server (MTS) 1.0 eliminates the need to work on low-level programming when building server applications, allowing developers to focus primarily on the server business logic. To illustrate MTS design and implementation decisions, we’ve built a sample Customer Maintenance program that exhibits the fundamental MTS development and deployment tasks. As we walk through the client and server code, we will point out requirements and suggestions for building your applications according to the MTS programming model. We’ve provided a glossary of MTS terminology in the sidebar “An MTS Glossary” for your general reference.

What is MTS?

MTS is a component-based programming model and runtime environment for developing, deploying, and managing high-performance, scalable, and robust enterprise Internet and intranet server applications. MTS 1.0, which was released in December 1996, combines the power, flexibility, and low cost of desktop applications with the mission-critical transaction processing features previously found on high-end mainframes. MTS requires Microsoft Windows NT® 4.0 and accommodates both Windows NT and Windows® 95-based clients (with DCOM support).

MTS Components

Because MTS uses a component-based application
development model with a transaction processing run­time infrastructure, you break down your business logic into ActiveX™ components that can be updated and managed easily. You use your favorite development tool—Visual Basic®, Visual C++®, Visual J++, COBOL, Powerbuilder, Optima++, or Vision Builder—to build ActiveX single-user components as in-process DLLs. The DLLs are then installed into the MTS runtime environment for execution. You can create your application from components you build yourself, components you share with other applications, or components you buy from a third party.

MTS Explorer

The MTS Explorer helps you package, deploy, and administer your applications. MTS applications consist of one or more packages—a set of components that perform related application functions that are organized into one deployment unit. You can use the MTS Explorer’s graphical user interface to perform development, deployment, and administration tasks on your package files. The MTS Explorer hierarchy depicts how the items in the runtime environment are organized so that you can manipulate your applications on the package, component, interface, and method levels. The MTS Explorer interface lets you perform tasks ranging from creating a new package to providing a brief description of a method on an interface for administrators to reference.

MTS Application Clients

With MTS, you have a choice of clients. MTS supports HTML browser clients and Win32® clients built using any of the development tools mentioned previously. Figure 1 shows how the two client types communicate with MTS components. A Win32 client communicates over DCOM with an MTS component running in the MTS runtime environment. A browser client communicates with Microsoft Internet Information Server (IIS) or any other Internet server capable of invoking ActiveX components. For example, you can write Active Server Pages (ASP) scripts to invoke ActiveX components running in MTS.

Figure 1 Three-tier Architecture with MTS

MTS Runtime Environment

Components in an MTS application execute in the MTS runtime environment. This runtime infrastructure:

MTS components can access data using ODBC. Anything layered above ODBC may also be used to access data, in­cluding ActiveX Data Objects (ADO), OLE DB provider for ODBC, and Remote Data Objects (RDO). Since ODBC 3.0 Driver Manager is an MTS resource dispenser, data accessed via ODBC is automatically protected by your object’s transaction. In order for this to work, an ODBC-compliant database must have a thread-safe driver that operates without thread affinity.

If ODBC is used from within a transactional component, then the ODBC driver must also support the SQL_ATTR_
ENLIST_IN_DTC connection attribute. This is how the ODBC Driver Manager asks the ODBC driver to enlist a connection on a transaction. You can make your component transactional by setting the transaction property for your component in the MTS Explorer.

Currently, SQL Server™ 6.5 is the only database with an ODBC driver that satisfies both criteria. Many databases support the first criteria and are working on providing support for the second. If you are working with a database that does not have a resource dispenser that can recognize MTS transactions, contact your database vendor to obtain the required support.

Other MTS resource dispensers include the Microsoft beta products codenamed “Cedar” and “Falcon.” Cedar is used to access CICS and IMS transaction monitor mainframes (see http://www.microsoft.com/transaction/ for details). Falcon (Microsoft MSMQ) is a message queuing system (see http://www.microsoft.com/msmq/). Since Cedar and MSMQ are resource dispensers, any work done is guaranteed to be protected by the object’s transaction when used by an MTS component. The MTS Beta SDK can be used to build additional resource dispensers.

MTS Transaction Coordinator

MTS uses the services of Microsoft Distributed Transaction Coordinator (DTC) for transaction coordination. DTC is a system service that coordinates transactions that span multiple resource managers. Work can be committed as a single transaction even if it spans multiple resource managers, potentially on separate machines. DTC was first released as part of Microsoft SQL Server 6.5 and is included as part of MTS. It implements a two-phase commit protocol that ensures the transaction outcome (either commit or abort) is consistent across all resource managers involved in a transaction. DTC supports resource managers that implement OLE transactions, X/Open XA protocols, and LU 6.2 Sync Level 2.

Customer Maintenance Sample

To illustrate the process of building applications to the MTS programming model, we wrote a simple, three-tier sample application called Customer Maintenance that updates customer information in a database. We built Customer Maintenance using Visual Basic 5.0 Enterprise Edition, ADO, and SQL Server 6.5 for the database. Figure 2 illustrates the architecture of the sample application.

Figure 2 Customer Maintenance Architecture

The user interface of the Customer Maintenance client consists of two forms for data entry. Figure 3 shows the update form to add or modify customer infor­mation stored in the customer table of the database. The customer form contains the subroutines shown in Figure 4. If the user selects Search, a second form is displayed to provide search capability across the database. Users can enter any part of a customer name to display a list of customers, and then select the customer name for modification. Figure 5 shows the user interface for searching customer records, and Figure 6 lists the subroutines contained in the form.

Figure 3 Update Form

Figure 4 frmCustomer Subroutines

Subroutine Name Description

cmdFind_Click Find a single customer record from the database calling the LookupCustomer­ByEmail method on the Customer object.

cmdSearch_Click Open the frmCustomerSearch to allow user to select a customer from a list box.

cmdClear_Click Clear all fields on a form.

cmdAdd_Click Add a new customer to the database using the Add method on the Customer object.

cmdSave_Click Save an existing customer using the Update method on the Customer object.

cmdExit_Click Exit and end application

FillFields Fill the fields on the form with the data from the recordset returned by the Find method.

ClearFields Clear all the fields on the form.

FindCustomer Find a customer in the database using the Find method on the Customer object.

Form_KeyDown Executes code that implements the shortcut keys for the command buttons on the form. The KeyPreview property on the form is set to True causing the shortcuts (Alt-I) to be processed in this method. We did this because we used graphics on our command buttons without captions.

Figure 5 Searching Customer Records

Figure 6 frmCustomerSearch Subroutines

cmdSearch_Click Search the customer database finding all last names matching the selection entered by using the LookupCustomerByLastName method on the Customer object.

CmdSelect_Click Select a customer record from the list box and fill the customer form with the customer record by using the Find method on the Customer object.

cmdExit_Click Hide the frmCustomerSearch form

Form_KeyDown Executes code that implements the shortcut keys for the command buttons on the form. The KeyPreview property on the form is set to True causing the shortcuts (Alt-I) to be processed in this method. We did this because we used graphics on our command buttons without captions.

Note that in the client code (see Figure 7), the ERROR_NUMBER constant is used for setting the error number in the application. The ERROR_
NUMBER’s value is set to a value higher than the standard Visual Basic error numbers to avoid any conflicts, and can be used to generate application errors. The client code also contains a constant, strDSN, that points to the location of the DSN file used for this application. The DSN file is a text file that contains information about the database to be used for this application.

Figure 7 Customer Maintenance Client

CustomerMod.bas

' we always return the same error number

Public Const ERROR_NUMBER = vbObjectError + 0

Public Const strDSN = "Classified.dsn"

Public g_strEmail as String

frmCustomer.frm

Option Explicit

Dim objCustomer As MTS_Customers.Customers

Private Sub Form_Load()

On Error GoTo ErrorHandler

Set objCustomer = CreateObject("MTS_Customers.Customers")

Exit Sub

ErrorHandler:

cmdExit_Click

MsgBox "An error occurred in creating the Customer Component."

End Sub

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

If Shift <> vbAltMask Then

Exit Sub

Else

Select Case KeyCode

Case vbKeyI

cmdFind_click

Case vbKeyR

cmdSearch_Click

Case vbKeyC

cmdClear_Click

Case vbKeyA

cmdAdd_Click

Case vbKeyS

cmdSave_Click

Case vbKeyX

cmdExit_Click

End Select

End If

End Sub

Private Sub cmdSearch_Click()

On Error GoTo ErrorHandler

frmCustomerSearch.Show vbModal, Me

Exit Sub

ErrorHandler:

MsgBox "An error occurred loading the customer search form."

End Sub

Private Sub cmdFind_click()

On Error GoTo ErrorHandler

If txtEmail.Text = "" Then

MsgBox "ERROR: Email is required to lookup customer.", , Me.Caption

txtEmail.SetFocus

Else

FindCustomer

txtEmail.SetFocus

End If

Exit Sub

ErrorHandler:

MsgBox "An error occurred in finding the customer."

End Sub

Private Sub cmdClear_Click()

ClearFields

End Sub

Private Sub cmdAdd_Click()

On Error GoTo ErrorHandler

objCustomer.Add strDSN, txtEmail, txtLastName,

txtFirstName, txtAddress, txtCity,

txtState, txtPostalCode, txtPhoneNumber

txtEmail.SetFocus

MsgBox "Customer record has been added.", , Me.Caption

Exit Sub

ErrorHandler:

MsgBox "ERROR: Your record was not added. This customer may already exist.",

, Me.Caption

txtEmail.SetFocus

End Sub

Private Sub cmdSave_Click()

On Error GoTo ErrorHandler

If txtEmail <> "" Then

objCustomer.Update strDSN, txtEmail, txtLastName,

txtFirstName, txtAddress, txtCity,

txtState, txtPostalCode, txtPhoneNumber

txtEmail.SetFocus

MsgBox "Customer record has been updated.", , Me.Caption

Else

Err.Raise ERROR_NUMBER, "Email is required."

End If

Exit Sub

ErrorHandler:

MsgBox "ERROR: " & Err.Description & ". Customer record was not updated.",

, Me.Caption

txtEmail.SetFocus

End Sub

Private Sub cmdExit_Click()

End

End Sub

Public Sub FillFields(rsCustomer As ADODB.Recordset)

txtEmail.Text = rsCustomer!Email

txtLastName.Text = rsCustomer!LastName

txtFirstName.Text = rsCustomer!FirstName

txtAddress.Text = rsCustomer!Address

txtCity.Text = rsCustomer!City

txtState.Text = rsCustomer!State

txtPostalCode.Text = rsCustomer!PostalCode

txtPhoneNumber.Text = rsCustomer!PhoneNumber

End Sub

Private Sub ClearFields()

txtEmail.Text = ""

txtLastName.Text = ""

txtFirstName.Text = ""

txtAddress.Text = ""

txtCity.Text = ""

txtState.Text = ""

txtPostalCode.Text = ""

txtPhoneNumber.Text = ""

End Sub

Public Sub FindCustomer()

On Error GoTo ErrorHandler

Dim rsCustomer As ADODB.Recordset

Set rsCustomer =

objCustomer.LookupCustomerByEMail(strDSN, txtEmail.Text)

If rsCustomer.EOF = True And rsCustomer.BOF = True Then

MsgBox "ERROR: No record was found.", , Me.Caption

Dim strEmail As String

strEmail = txtEmail.Text

ClearFields

txtEmail.Text = strEmail

Else

FillFields rsCustomer

End If

Exit Sub

ErrorHandler:

MsgBox "Error in finding customer."

End Sub

FrmCustomerSearch.frm

Option Explicit

Dim arrCustomerEmail() As String

Dim objCustomer As MTS_Customers.Customers

Private Sub cmdSelect_Click()

On Error GoTo ErrorHandler

If lstCustomers.ListIndex < 0 Then

MsgBox "No customer has been selected."

txtSearch.SetFocus

Exit Sub

End If

g_strEmail = arrCustomerEmail(lstCustomers.ListIndex)

Me.Hide

frmCustomers.Show

frmCustomers.txtEmail.SetFocus

Exit Sub

ErrorHandler:

MsgBox "An error occurred in selecting the customer record"

End Sub

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

If Shift <> vbAltMask Then

Exit Sub

Else

Select Case KeyCode

Case vbKeyR

cmdSearch_Click

Case vbKeyX

cmdExit_Click

End Select

End If

End Sub

Private Sub cmdExit_Click()

Me.Hide

End Sub

Private Sub cmdSearch_Click()

On Error GoTo ErrorHandler

Dim strListData As String

Dim rsCustomer As ADODB.Recordset

lstCustomers.Clear

Set rsCustomer =

objCustomer.LookupCustomerByLastName

(strDSN, txtSearch.Text)

Dim i As Integer

i = 0

Do Until rsCustomer.EOF

lstCustomers.AddItem rsCustomer!LastName & ",

" & rsCustomer!FirstName

ReDim Preserve arrCustomerEmail(i)

arrCustomerEmail(i) = rsCustomer!Email

i = i + 1

rsCustomer.MoveNext

Loop

Exit Sub

ErrorHandler:

MsgBox "An error occurred in search for customer."

End Sub

Private Sub Form_Load()

On Error GoTo ErrorHandler

Set objCustomer = CreateObject("MTS_Customers.Customers")

Exit Sub

ErrorHandler:

cmdExit_Click

MsgBox "An error occurred in creating the Customer Component."

End Sub

So, what else do you need to do to make MTS work with a Win32 client? This is the best part: there is nothing specific about a client communicating directly with an MTS middle-tier server other than meeting the standard ActiveX client programming requirements.

Customer Server Component

On the server, the sample application contains a single component, MTS_Custo­mers.Customers, that handles access and update requests from the client. The server Customer component is a middle-tier object that uses methods for finding, adding, and updating customer information in a database. The Customer component uses the “Requires a transaction” setting (we’ll tell you how to set this property in the MTS Explorer later), which means that all work done in the component will be protected by a transaction. The component can run in a transaction all by itself or may also be called as part of a larger transaction. The component itself only needs to care about its own work.

The component will essentially place its “vote” on the outcome of the transaction based on the success or failure of its own work. If the component is happy with the outcome, it will execute an MTS method to commit the transaction. Otherwise, the component will execute an MTS method to abort the transaction. The important point here is that the component does not ever need to know about what the other components are doing or the outcome of their work. Figure 8 shows the methods used in the Customer object. (See the “MTS Transactions” sidebar for a more detailed discussion.)

Figure 8 Customer Object Methods

Method Name Description

LookupCustomerByLastName Given all or part of a customer last name, return a customer recordset containing all matching records found.

LookupCustomerByEMail Given a customer email address, return a customer recordset containing one customer.

Add Add a customer record.

Update Update a customer record.

The first part of the server component sets the return value of the method Lookup­CustomerByLastName to ADODB.Recordset because we are going to remote a record­set back to the client. Note that we pass in the file­DSN for the database. By using the fileDSN, you can avoid hard­coding system DSN information into your program.

Option Explicit

Public Const ERROR_NUMBER=

vbObjectError + 0

' we always return the

' same error number

Option Explicit

Public Function

LookupCustomerByLastName

(ByVal fileDSN As String,

ByVal vLastName) As ADODB.Recordset

First, we need to get a reference to an object context for our server component. The object context is an intrinsic MTS runtime component that stores data specific to a component instance (including security and transaction information). ObjectContext also exposes methods that make up the MTS programming model.

Dim objContext As

ObjectContext

Set objContext =

GetObjectContext

On Error GoTo

ErrorHandler

We set the cursor location property on the customer recordset to the value adUse­ClientBatch so the recordset can be remoted back to the client. We then use a standard SQL query on the database to pull records of customers with the specified last name.

We use SetComplete on objContext to indicate to MTS that we are finished with this piece of work and no longer need the state in this component. This means a component can be returned to its initial state for future method invocations. Note that we have not written any explicit code supporting transactions. The MTS runtime environment handles transaction support if you specify (in the MTS Explorer) that your components require transactions. We’ll show you how to assign transactional settings when we deploy the Customer Maintenance package.

SetComplete also tells the MTS runtime that any resource manager changes can be committed. SetAbort tells the MTS runtime that the component is done with its work, but that any resource manager changes should be rolled back (aborted). If this component was part of a larger transaction, then the changes would be committed when
all the components had completed their work successfully (see Figure 9).

Figure 9 LookupCustomerByLastName Method
Public Function LookupCustomerByLastName

(ByVal fileDSN As String, ByVal vLastName) As Variant

Dim m_objContext As ObjectContext

Set m_objContext = GetObjectContext

On Error GoTo ErrorHandler

' Get customer information

Dim rsCustomer As New ADODB.Recordset

Dim strSQL As String

strSQL = "SELECT FULLNAME = (RTrim(LastName) + ',

' + RTrim(FirstName)),LastName, FirstName,

Address, City, State, PostalCode, PhoneNumber,

EMail FROM Customers Where LastName Like '" &

vLastName & "%' ORDER BY FULLNAME For Browse"

rsCustomer.CursorLocation = adUseClientBatch

rsCustomer.Open strSQL, "FILEDSN=" & fileDSN

' Cleanup object on the way out

objContext.SetComplete

Set LookupCustomerByLastName = rsCustomer

Exit Function

ErrorHandler:

' Cleanup object on the way out

objContext.SetAbort

Err.Raise Number:=ERROR_NUMBER,

Source:="MTS_Customers.Customers.LookupCustomerByLastName",

Description:=Err.Description

End Function

Next, we implement the LookupCustomerByEMail method (see Figure 10), which checks the database for a specified email string and returns a recordset to the client. To add a customer to the database, we use the Add method, which takes a number of parameters. To avoid expensive network round-trips, we recommend that you pass parameters instead of setting properties on the object.

Figure 10 LookupCustomerByEMail Method
Public Function LookupCustomerByEMail

(ByVal fileDSN As String, ByVal vEmail) As ADODB.Recordset

Dim objContext As ObjectContext

Set objContext = GetObjectContext

On Error GoTo ErrorHandler

' Get customer information

Dim rsCustomer As New ADODB.Recordset

Dim strSQL As String

strSQL = "Select * from Customers where Email ='" & vEmail & "'"

rsCustomer.CursorLocation = adUseClientBatch

rsCustomer.Open strSQL, "FILEDSN=" & fileDSN

' Cleanup object on the way out

objContext.SetComplete

' all went well -- return the customer

Set LookupCustomerByEMail = rsCustomer

Exit Function

ErrorHandler:

' Cleanup object on the way out

objContext.SetAbort

Err.Raise Number:=ERROR_NUMBER,

Source:="MTS_Customers.Customers.LookupCustomerByEMail",

Description:=Err.Description

End Function

We use a Connection component because we are not going to be returning a recordset to the client (see Figure 11). The Update method is very similar to the Add method. Again, we use the Connection component (see Figure 12).

Figure 11 Adding a Customer
Public Sub Add(ByVal fileDSN, ByVal strEMail As String,

ByVal strLastName As String,

ByVal strFirstName As String,

ByVal strAddress As String,

ByVal strCity As String, ByVal strState As String,

ByVal strPostalCode As String, ByVal strPhone As String)

Dim objContext As ObjectContext

Set objContext = GetObjectContext

On Error GoTo ErrorHandler

Dim strSQL As String

Dim Conn As New ADODB.Connection

strSQL = "INSERT Customers(Email, LastName, FirstName,

'Address, City, State, PostalCode, PhoneNumber)

VALUES ('" & strEMail & "', '" & strLastName & "',

'" & strFirstName & "', '" & strAddress & "',

'" & strCity & "', '" & strState & "',

'" & strPostalCode & "', '" & strPhone & "')"

Conn.Open "FILEDSN=" & fileDSN, "", ""

Conn.Execute strSQL

objContext.SetComplete

Exit Sub

ErrorHandler:

' Cleanup object on the way out

objContext.SetAbort

Err.Raise Number:=ERROR_NUMBER,

Source:="MTS_Customers.Customers.Customers.Add",

Description:=Err.Description

End Sub


Figure 12 Update Method
Public Sub Update(ByVal fileDSN, ByVal strEMail As String,

ByVal strLastName As String,

ByVal strFirstName As String,

ByVal strAddress As String,

ByVal strCity As String,

ByVal strState As String,

ByVal strPostalCode As String,

ByVal strPhone As String)

Dim objContext As ObjectContext

Set objContext = GetObjectContext

On Error GoTo ErrorHandler

Dim strSQL As String

Dim Conn As New ADODB.Connection

strSQL = "Update Customers Set " & "LastName = '" &

strLastName & "', " & "FirstName = '" &

strFirstName & "', " & "Address = '" &

strAddress & "', " & "City = '" & strCity &

"', " & "State = '" & strState & "', " &

"PostalCode = '" & strPostalCode & "', " &

"PhoneNumber = '" & strPhone & "' " &

"Where Email = '" & strEMail & "'"

Conn.Open "FILEDSN=" & fileDSN, "", ""

Conn.Execute strSQL

objContext.SetComplete

Exit Sub

ErrorHandler:

' Cleanup object on the way out

objContext.SetAbort

Err.Raise Number:=ERROR_NUMBER,

Source:="MTS_Customers.Customers.Customers.Update",

Description:=Err.Description

End Sub


You’ve probably noticed a general pattern in the implementation of each of the methods in the Customer server component—each method shares the following infrastructure in the code:
Public Sub DoWork()
Dim objContext As ObjectContext

Set objContext = GetObjectContext


' Do work.
' Everything okay.
objContext.SetComplete
Exit Sub

ErrorHandler:

' Cleanup object on the way out

objContext.SetAbort

' Report Error information

End Sub

In general, the majority of MTS application methods can be written for MTS components by following these steps:

  1. Get the MTS ObjectContext.

  2. Do work.

  3. If there is no error, tell MTS you are done and consistent using ObjectContext.SetComplete.

  4. Otherwise (Error), tell MTS you are done and are incon­sistent using ObjectContext.SetAbort.

The Customer component is a simple but complete representation of a typical MTS component. We did not include the methods associated with creating subcomponents or programmatic security in this sample. (A discussion of Just-In-Time activation appears in the “Just-In-Time Activation” sidebar.)

Preparing for Deployment

When building your application, think about development and deployment as two separate stages. Applications are partitioned into package files and then deployed and administered by the MTS Explorer. A package is an abstraction-representing component associated by security and fault isolation as well as a physical file format. The package file contains component and application information. The package file and corresponding component DLLs represent the deploy­able unit, which is distributed to one or more middle-tier server machines. Note that an MTS application can consist of one or more packages, just as a package can contain one or more components.

When creating an MTS application, you should carefully consider the design and deployment implications for package topology, partitioning of components across packages, package security configuration, and property configuration per component (such as transactions or security). The “Package Design” sidebar gives you a few pointers for designing your package application topology.

Opening the MTS Explorer, we selected the Packages Installed folder in the MTS Explorer hierarchy and started the Package Wizard by selecting File|New. Figure 13 illustrates how you can either create a new package or install a prebuilt package (such as a package provided by a third-party developer).

Figure 13 Package Wizard

After we created and named the new package, we installed the MTS_Custo­mer.DLL file into the package as a component. The MTS Explorer has an Install Component Wizard that walks you through the installation of a component (see Figure 14). You can also drag and drop your DLL into the component pane of the MTS Explorer to add a component to a package (see Figure 15).

Figure 14 Component Wizard

Figure 15 Adding a component to a package

After we set up our package, we right-clicked on the new component in the package to bring up the Properties page, which allows you to define transaction support, security, and activation. We set the transactions setting to “Requires a transaction” so that our component will automatically start a new transaction if one doesn’t already exist (see Figure 16). Note here that selecting a single radio button on a property page enables transactions in your component. You don’t have to write any code to define the scope of a transaction, such as Begin Transaction or End Transaction, because that functionality is built into MTS, just like declarative security and a number of other features.

Figure 16 Component Property Page

Once we set up our package, we used the export function in the MTS Explorer to export that package to a local directory. This generates a subdirectory called clients that contains a client install executable (see Figure 17). You can distribute that client executable through a share, a Web page, or email.

Figure 17 The Client Subdirectory

Deploying the Application

The Customer Maintenance sample application consists of five files (not including database configuration). On the client side, both Customer­Maint.exe and Customers.exe are deployed to a set of client machines. MTS handles the configuration of client applications for server packages, while the distributor is responsible for delivering the client executable to users. When the user runs Cus­tomers.exe, the client install file will configure the client machine to activate the Customer component on a remote server.

Note that the current implementation of client install configures the remote server as the server machine that created the package. Alternatively, you can use the DCOM configuration utility (DCOMCNFG.EXE) to modify the remote server to which the client connects.

The other two files, MTS_Customer.dll and Custo­mers.pak, are deployed to
one or more server machines. You can distribute these server components across multiple servers and statically bind specific client machines to specific servers. Balancing the load across several server machines increases app­lication performance and scalability.

Once Customers.pak and MTS_Customer.dll are physically on or accessible from the server machine, the MTS Explorer can be used to install the Customers package in-to MTS. The MTS Explorer provides remote administration, so packages can be deployed across several servers from a single instance of MTS Explorer.

If you used declarative security on your application, the next step in setting up the MTS server is to configure each security role defined in the Customer package with specific Windows NT users and groups. Package developers are encouraged to provide documentation for those deploying MTS applications (specifically, detailed information on security roles and call authorization between components and component interfaces). If a package does not contain documentation about security roles, you can use the MTS Explorer to browse role information.

Monitoring the Application

You can also use the MTS Explorer to monitor your applications. After you have deployed the Customer Maintenance application across a set of clients and servers, you can review activity on one or more servers. The component status view provides information per component:

Objects The total number of objects that have been allocated within the server process.

Activated The total number of objects being used by clients.

In Call The total number of ob­jects that are currently executing a client call.

In addition to component status, you can monitor transaction status using the Transaction Statistics view (see Figure 18). Statistics include current active transactions, total  committed transactions, and total aborted transactions.

Figure 18 Transaction Statistics

Conclusion

We just stepped through the implementation, packaging, and deployment of a simple three-tier MTS application. To really learn what MTS is all about, what problems it solves, and what issues it raises, you must build an MTS application on your own. Start out with an application that is not critical-path for your business, but performs a specific business function. We recommend starting a “3-2-1”effort, meaning that you identify a business application that can be implemented using a three-tier architecture, using two people, in one month. This will get you comfortable with MTS and by the end of the project you will have assembled a working enterprise application.

If you don’t already have MTS 1.0, you can download an eval­uation copy from http://www.microsoft.com/transaction/. Try it for yourself and see what the developer community is beginning to realize: if you’re not using MTS, you’re coding more than you should for server applications. u

An MTS Glossary

ActiveX A set of technologies that enables software components to interact with one another in a networked environment, regardless of the language in which they were created. ActiveX is built on the Component Object Model (COM).

Administrator One who uses the Microsoft Transaction Server (MTS) Explorer to install, configure, and manage MTS components and packages.

Business rule The combination of validation edits, logon verifications, database lookups, policies, and algorithmic transformations that constitute an enterprise’s way of doing business. Also known as business logic.

Catalog The MTS data store that maintains configuration information for components, packages, and roles. The catalog is administered by using the MTS Explorer.

Client An application or process that requests a service from some process or component.

COM (Component Object Model) An open architecture for cross-platform development of client/server applications based on object-oriented technology. Clients have access to an object through interfaces implemented on the object. COM is language-neutral, so any language that produces ActiveX components can also produce COM applications.

Component A discrete unit of code built on ActiveX technologies that delivers a well-specified set of services through well-specified interfaces. Components provide the objects that clients request at runtime.

Concurrency The appearance of simultaneous execution of processes or transactions by interleaving the execution of multiple pieces of work.

Context The state that is implicitly associated with a given MTS object. The context contains information about the object’s execution environment, such as the identity of the object’s creator and, optionally, the transaction encompassing the work of the object. An object’s context is similar in concept to the process context that an operating system maintains for an executing program. The MTS runtime environment manages a context for each object.

Declarative security The security that is configured with the MTS Explorer. Access to packages, components, and interfaces is controlled by defining roles. Roles determine which users are allowed to invoke interfaces in a component. See also programmatic security.

Distributed COM (DCOM) DCOM is an object protocol that enables ActiveX components to communicate directly with each other across a network. DCOM is language-neutral, so any language that produces ActiveX components can also produce DCOM applications.

Data source name (DSN) The name that applications use to request a connection to an ODBC data source.

Dynamic-link library (DLL) A file that contains one or more functions that are compiled, linked, and stored separately from the processes that use them. The operating system maps the DLLs into the address space of the calling process when the process is starting or while it’s running.

Identity A package property that specifies the user accounts that are allowed to access the package. It can be a specific user account or a group of users within a Windows NT domain.

In-doubt transaction A transaction that has been prepared but hasn’t received a decision to commit or abort because the server coordinating the transaction is unavailable.

In-process component A component that runs in a client’s process space. This is typically a DLL.

Just-In-Time activation The ability for an MTS object to be activated only as needed for executing requests from its client. Objects can be deactivated even while clients hold references to them, allowing otherwise idle server resources to be used more productively.

Interface A group of logically related operations or methods that provides access to a component object.

MTS component A COM component that executes in the MTS runtime environment. An MTS component must be a DLL, implement a class factory to create objects, and describe all of the component’s interfaces in a type library for standard marshaling.

Microsoft Distributed Transaction Coordinator (DTC) A transaction manager that coordinates transactions that span multiple resource managers. Work can be committed as an atomic transaction even if it spans multiple resource managers, potentially on separate computers.

MTS Explorer A graphical user interface used to configure and manage MTS components within a distributed computer network.

MTS object A COM object that executes in the MTS runtime environment and follows the MTS programming and deployment model.

ODBC resource dispenser A resource dispenser that manages pools of database connections for MTS components that use the standard ODBC programming interfaces.

Out-of-process component A component that runs in a separate process space from its client. MTS enables components implemented as DLLs to be used out-of-process from the client by loading the components into surrogate server processes.

Package A set of components that perform related application functions. All components in a package run together in the same MTS server process. A package is a trust boundary that defines when security credentials are verified. It’s also a deployment unit for a set of components. The MTS Explorer can create packages.

Package file A file that contains information about the components and roles of a package. A package file is created using the package export function of the MTS Explorer. When a package is created, the associated component files (DLLs, type libraries, and proxy-stub DLLs, if implemented) are copied to the same directory where the package file was created.

Pooling A performance optimization based on using collections of pre-allocated resources, such as objects or database connections. Pooling results in more efficient resource allocation.

Programmatic security The procedural logic provided by a component to determine if a client is authorized to perform the requested operation. See also declarative security.

Resource dispenser A service that provides the synchronization and management of nondurable resources within a process, providing for simple and efficient sharing by MTS objects. For example, the ODBC resource dispenser manages pools of database connections.

Resource Dispenser Manager A DLL that coordinates work among a collection of resource dispensers.

Resource manager A system service that manages durable data. Server applications use resource managers to maintain the durable state of the application, such as the record of inventory on hand, pending orders, and accounts receivable. The resource managers work in cooperation with the transaction manager to provide the application with a guarantee of atomicity and isolation (using the two-phase commit protocol). Microsoft SQL Server is an example of a resource manager.

Role A symbolic name that defines a class of users for a set of components. Each role defines which users are allowed to invoke interfaces on a component.

Remote component A component used by a client on a different computer.

Server process A process that hosts MTS components. An MTS component can be loaded into a surrogate server process, either on the client’s computer (local) or on another computer (remote). It can also be loaded into a client application process (in-process).

Shared property A variable that is available to all objects in the same server process via the Shared Property Manager. The value of the property can be any type that can be represented by a variant.

Stateful object An object that holds private state accumulated from the execution of one or more client calls.

Stateless object An object that doesn’t hold private state accumulated from the execution of one or more client calls.

Transaction A unit of work that is done as an atomic operation—that is, the operation succeeds or fails as a whole.

Transaction context An object used to allow a client to dynamically include one or more objects in one transaction.

Transaction manager A system service responsible for coordinating the outcome of transactions in order to achieve atomicity. The transaction manager ensures that the resource managers reach a consistent decision on whether the transaction should commit or abort.

Two-phase commit A protocol ensuring that transactions applying to more than one server are completed on all servers or none at all. Two-phase commit is coordinated by the transaction manager and supported by resource managers.

MTS Transactions
Microsoft Transaction Server simplifies the task of devel­op­ing application components by letting you perform work with transactions. This protects applications from anomalies caused by concurrent updates or system failures.

Transactions maintain the following properties, together known as ACID:

  • Atomicity ensures that all the updates completed under a specific transaction are committed (and made durable) or that they get aborted and rolled back to their previous state.

  • Consistency means that a transaction is a correct trans­formation of the system state, preserving the state invariants.

  • Isolation protects concurrent transactions from seeing each other’s partial and uncommitted results, which might create inconsistencies in the application state. Resource managers use transaction-based synchronization protocols to isolate the uncommitted work of active transactions.

  • Durability means that committed updates to managed resources (such as a database record) survive failures, including communication failures, process failures, and server system failures.

Transactional logging even allows you to recover the durable state after disk media failures. The intermediate states of a transaction aren’t visible outside the transaction, and either all of the work happens or none of it does. This allows you to develop application components as if each transaction executes sequentially and without regard to concurrency. This is a tremendous simplification for application developers.

If you declare that a component is transactional, MTS associates transactions with the component’s objects. When an object’s method is executed, the services that resource managers and resource dispensers perform on its behalf execute under a transaction. This can also include work that it performs for other MTS objects. Work from multiple objects can be composed into a single atomic transaction. In our Customer Maintenance sample application our component is transactional.

Transaction Attributes

Every MTS component has a transaction attribute that is recorded in the MTS catalog. MTS uses this attribute during object creation to determine whether a new transaction should be created for the object, whether the object should use the object creator’s transaction, or whether the object should run without a transaction. Components that access transactional resources (for example, database records) can ensure that their objects are always created within a transaction. If the object is created from a context that has a transaction, the new context inherits that transaction; otherwise, the system automatically initiates a transaction.

You can set components that perform non-database work (such as calculations) to support, but not require, transactions. If this component is called and a transaction has already been started, then the work of the component can participate in the transaction. If the non-database work of the component fails, the transaction would fail and any other database work that other components had done would be rolled back.

Resource dispensers can use the context object to provide transaction-based services to the MTS object. For example, when an object executing within a transaction allocates a database connection by using the ODBC resource dispenser, the connection is automatically enlisted on the transaction. All database updates using this connection become part of the transaction, and are either atomically committed or aborted.

How Objects Can Participate

The IObjectContext interface has methods that enable an MTS object to participate in determining a transaction’s outcome. The SetComplete, SetAbort, DisableCommit, and EnableCommit methods work in conjunction with the component’s transaction attribute to allow one or more objects to be simply and safely composed within transactions.

Both SetComplete and SetAbort deactivate the object on return from the method. The object is reactivated on the next call that requires object execution.

Objects that need to retain state across multiple calls from a client can protect themselves from having their work committed prematurely by the client. By calling DisableCommit before returning control to the client, the object can guarantee that its transaction cannot be successfully committed without the object doing its remaining work and calling EnableCommit.

Just-In-Time Activation
Traditionally, when you design applications, you have two options for how to handle your object. The first option is for a client to create, use, and release an object. The next time it needs the object, it creates it again. This kind of object maintains state only across method invocation. The second option is for a client to create an object and hold onto it until the client no longer needs it. These objects maintain state for the object’s lifetime.

When you use stateless components, you conserve server resources. However, as your application scales to more users, the performance of your application may decline. If the object is on a remote computer, there must be a network round-trip each time an object is created, which degrades performance. Objects that maintain state boost performance for an application with a small number of users, but are extremely expensive in terms of server resources in a large-scale application. While either of these approaches might be adequate for a small-scale application, as your application scales up, they’re both inefficient. With MTS, Just-In-Time activation provides the best of both approaches while avoiding the disadvantages of each.

For example, in the Customer Maintenance sample application, the Customer client controls the Customer server object’s life cycle. Clients hold onto server resources even when they are idle. As more clients are added, there will be a proportional increase in the number of allocated objects and database connections. A Customer object doesn’t need to maintain any private state to correctly process new requests from its client, nor does it need to maintain its database connection between calls. The main problem in this scenario is that the MTS runtime environment can’t reclaim the object’s resources until the client explicitly releases the object. If you have to depend on your clients to manage your object’s resources, you can’t build a scalable component.

We implemented Just-In-Time activation in the Customer server component by adding a few lines of code. When the Customer object calls SetComplete, the component notifies the MTS runtime environment that it should be deactivated as soon as it returns control to the client. This allows the MTS runtime environment to release the object’s resources, including any database connection it holds prior to the object’s release. The Customer client continues to hold a reference to the deactivated Customer object. Just-In-Time activation allows you to conserve system resources while allowing your application to scale to multiple users.


Package Design
MTS introduces packages as an application file unit, and it may not be immediately obvious how to partition your application across MTS packages. Here are a few points to consider when designing your package application topology.

Fault Isolation By default, components sharing the same package will share the same server process. (A server process is a system process that hosts application component execution.) Note that there are exceptions
to this, depending on your activation settings. Fault isolation can be achieved by placing components in different packages, since each package runs in a separate server process. For example, you may be hosting an online sports score Web site with components written for each major sport (basketball, soccer, and so on). When you bring a new sport online (such as telemark extreme skiing), isolate your telemark component in its own package. If the telemark component causes an access violation, the failure will not affect the other sporting event components that are running in one or more different server processes.

Activation Currently, activation settings exist at the component level:

Ý In the creator’s process

Ý In a server process on this computer

Ý In a server process on a remote computer

We recommend that developers avoid using remote as a setting because MTS provides a simpler way of setting up remote components using the Remote Computer and Remote Component folders in the MTS Explorer hierarchy. For more information about pulling or pushing components between computers, refer to the Administrator’s Guide in the MTS 1.0 Help documentation.

Activation by default runs components in a server process on the local computer (in-process). When building a library of utility components (such as tax or zipcode components) with components used across a variety of packages, create a utility package specifying all components to run in the creator’s process. Note that in-process components do not support declarative security or offer the benefits of process isolation. However, the efficiency gained from calling in-process utility components may outweigh process isolation or security concerns.

Security Isolation MTS defines a rich declarative security model using security roles that can be defined during deployment in the MTS Explorer. Security roles represent a logical group of users that are mapped to Windows NT domain users and groups during the deployment of the package. You can define declarative authorization checking by applying roles to components and component interfaces using the MTS Explorer. Applying a security role to a component specifies that anyone who is a member of the security role is allowed to call the component.

Security authorization is checked when a method call crosses a package boundary, such as when a client calls into a package or two packages call each other. No security checking is performed when two components that are running in the same server process call one another. In other words, components that share packages should trust one another.


Learning More About Microsoft Transaction Server
Microsoft Transaction Server Evaluation Kit 2 The MTS Evaluation Kit includes a 120-day evaluation version of MTS, white papers and NetShow presentations by the MTS architects, and sample MTS applications, including a Visual Basic-based application and a comprehensive Web-based application. You can order the evaluation kit from the MTS Web page at http://www.microsoft.com/transaction/.

Microsoft Transaction Server 1.0 Online Help Online help is installed by MTS setup. To view the help files after installing MTS, from the Start menu click Programs| Microsoft Transaction Server|Help.

Microsoft Transaction Server Readme The readme is installed by MTS setup. To view the readme after installing MTS, from the Start menu click Programs|Microsoft Transaction Server|Readme.

Microsoft Transaction Server Software Development Kit For advanced developers, MTS provides a beta SDK that lets you build resource managers or resource dispensers that work with your MTS application. The SDK also contains documentation and examples for programming support for XA-compliant resource managers and viewing MTS events. You can also utilize the SDK to facilitate deployment and administration of a package. The administrative objects in the SDK can be used to program MTS Explorer tasks such as updating a package property.
You can download the MTS Beta SDK from the MTS
Web page.

Web sites, FTP sites, public newsgroups, and FAQs The MTS Web page can be found at http://www.microsoft.com/transaction/. The MTS public FTP site can be found at ftp.microsoft.com. You can use anonymous FTP to access the site by entering “anonymous” as your user name, and your email id as your password. After you have logged in, enter “cd bussys/viper” to gain access to the MTS directories and files. The Microsoft Transaction Server public newsgroups and FAQs can be found through the MTS Support Web page.

To obtain complete source code listings, see page 5.