Sie sind auf Seite 1von 491

Scot Hillier’s COM+ Programming

with Visual Basic


®

Scot Hillier

800 East 96th St., Indianapolis, Indiana, 46240 USA


Copyright © 2000 by Sams Publishing ASSOCIATE PUBLISHER
FIRST EDITION Bradley L. Jones

All rights reserved. No part of this book shall be reproduced, stored in a ACQUISITIONS EDITOR
retrieval system, or transmitted by any means, electronic, mechanical, photo- Sharon Cox
copying, recording, or otherwise, without written permission from the pub-
DEVELOPMENT EDITOR
lisher. No patent liability is assumed with respect to the use of the information
Susan Shaw Dunn
contained herein. Although every precaution has been taken in the preparation
of this book, the publisher and author assume no responsibility for errors or MANAGING EDITOR
omissions. Neither is any liability assumed for damages resulting from the use Charlotte Clapp
of the information contained herein. For information, address Sams Publishing,
PROJECT EDITOR
A division of Macmillan Computer Publishing, 201 W. 103rd St., Indianapolis,
Paul Schneider
IN 46290.
International Standard Book Number: 0-672-31973-X COPY EDITOR
Rhonda Tinch-Mize
Library of Congress Catalog Card Number: 00-102598
INDEXER
Printed in the United States of America
Chris Barrick
First Printing: September 2000
PROOFREADER
03 02 01 00 4 3 2 1 Kimberly Campanello
Interpretation of the printing code: the rightmost double-digit number is the
TECHNICAL EDITOR
year of the book’s printing; the rightmost single-digit, the number of the
Rick Anderson
book’s printing. For example, a printing code of 98-1 shows that the first print-
ing of the book occurred in 1998. TEAM COORDINATOR
Composed in Function Condensed, AGaramond and MCPdigital by Macmillan Meggo Barthlow
Computer Publishing SOFTWARE SPECIALISTS
William Eland, Jr.
Trademarks Dan Scherf
All terms mentioned in this book that are known to be trademarks or service
marks have been appropriately capitalized. Sams Publishing cannot attest to INTERIOR DESIGNER
the accuracy of this information. Use of a term in this book should not be Anne Jones
regarded as affecting the validity of any trademark or service mark. COVER DESIGNER
Aren Howell
Warning and Disclaimer
Every effort has been made to make this book as complete and as accurate as LAYOUT TECHNICIANS
possible, but no warranty or fitness is implied. The information provided is on Ayanna Lacey
an “as is” basis. The author and the publisher shall have neither liability nor Heather Hiatt Miller
responsibility to any person or entity with respect to any loss or damages aris- Stacey Richwine-DeRome
ing from the information contained in this book or from the use of the CD or
programs accompanying it.
Contents at a Glance
Part I Understanding COM+ Applications
1 Windows DNA and COM+ 9
2 Administering COM+ 27
3 Designing COM+ Applications 53
4 COM+ Application Fundamentals 83

Part II Data Services


5 Accessing Data with COM+ 113
6 COM+ Data Components 149
7 COM+ Transactions 181

Part III Business Services


8 COM+ Security 207
9 COM+ Business Features 231
10 Asynchronous COM+ Applications 255

Part IV User Services


11 COM+ and the Internet 281
12 COM+ and Win32 311
13 Integrating COM+ with Groupware 331
14 Debugging and Deploying COM+ Applications 353
15 COM+ Catalog Administration 377

Part V PubsOnLine.com
16 Designing the PubsOnLine.com Application 391
17 Building the PubsOnLine.com Application 417
Index 449
Contents
INTRODUCTION 1
How This Book Is Organized ..................................................................1
Part I: Understanding COM+ Applications........................................1
Part II: Data Services..........................................................................2
Part III: Business Services..................................................................3
Part IV: User Services ........................................................................3
Part V: PubsOnLine.com ....................................................................4
Conventions Used in This Book ..............................................................5

PART I UNDERSTANDING COM+ APPLICATIONS 7

1 WINDOWS DNA AND COM+ 9


Windows 2000 Services ........................................................................11
Active Directory ..............................................................................12
Internet Information Server 5.0 ........................................................12
Message Queuing ............................................................................14
Universal Data Access ......................................................................14
XML Support....................................................................................14
Network Load Balancing..................................................................16
Component Services ........................................................................16
Tiered Architecture Overview................................................................18
Two-Tier Architecture ......................................................................19
Three-Tier Architecture ....................................................................21
Establishing a Test Environment ..........................................................23
Windows 2000 Advanced Server......................................................24
SQL Server 2000 ..............................................................................26
Visual Studio ....................................................................................26

2 ADMINISTERING COM+ 27
The Component Services Explorer........................................................28
Computer Properties ........................................................................29
Application Properties ......................................................................34
The System Application ..................................................................40
Creating Applications ......................................................................40
Component Properties ......................................................................42
Installing COM+ Components into an Application ........................46

3 DESIGNING COM+ APPLICATIONS 53


Assessing Functional Requirements ......................................................54
Problem Statement............................................................................54
Gathering Requirements ..................................................................55
Assessing Requirements ..................................................................57
Describing the System ..........................................................................58
Identifying Actors and Use Cases ....................................................59
Documenting the Use Cases ............................................................60
Flow Charts ......................................................................................64
Creating the Paper Prototype ................................................................65
System Modeling..............................................................................66
Database Model ................................................................................66
Logical Model ..................................................................................67
Three-Tier Diagram..........................................................................69
4 COM+ APPLICATION FUNDAMENTALS 83
Understanding Contexts ........................................................................84
Object Activation ..................................................................................88
Communicating with the Context ....................................................93
State Management ............................................................................96
The ObjectControl Interface ............................................................99
Managing Shared Properties................................................................102
SharedPropertyGroupManager ................................................102
SharedPropertyGroup................................................................102
SharedProperty ..........................................................................103

PART II DATA SERVICES 111

5 ACCESSING DATA WITH COM+ 113


OLEDB Session Pooling ....................................................................114
Controlling the Number of Pools ..................................................115
Tuning Session Pooling ..................................................................117
Understanding Data Transportation ....................................................123
Understanding Cursors ..................................................................123
Understanding Transports and Payloads ........................................125
Delimited Strings............................................................................126
Variant Arrays ................................................................................127
Disconnected Recordsets................................................................129
Property Bags ................................................................................131
Conclusion ......................................................................................134
XML ....................................................................................................134
XML Fundamentals........................................................................135
The Stream Object..........................................................................139
Web Services and SOAP ................................................................141
Updating Records ................................................................................142
Handling Collisions ........................................................................143
vi
SCOT HILLIER’S COM+ PROGRAMMING WITH VISUAL BASIC

6 COM+ DATA COMPONENTS 149


Encapsulating Stored Procedures ........................................................151
Parameter Passing ................................................................................154
Strong Function Signatures ............................................................154
Variant Arrays ................................................................................155
XML ..............................................................................................158
Error Handling ....................................................................................161
Polymorphic Interfaces ........................................................................163
Understanding Polymorphism ........................................................164
Creating Standards..........................................................................165
The DNA Payload................................................................................167
Overview ........................................................................................169
Dataset Properties and Methods ....................................................169
Field Object Properties ..................................................................170
Passing Parameters with the DNA Payload ..................................170
Returning Data with the DNA Payload..........................................173
Displaying HTML with the DNA Payload ....................................174
Conclusion ..........................................................................................175

7 COM+ TRANSACTIONS 181


Understanding Transaction Attributes ................................................182
The Microsoft Distributed Transaction Coordinator ..........................183
Transactional Components ..................................................................184
Understanding Transaction Context ..............................................185
Voting in Transactions ....................................................................190
Monitoring Transactions ......................................................................198

PART III BUSINESS SERVICES 205

8 COM+ SECURITY 207


Distributed Security ............................................................................208
Certificates......................................................................................208
Kerberos Protocol ..........................................................................209
Active Directory ..................................................................................210
Single Sign-On ..............................................................................211
Microsoft Installer ..........................................................................211
Personalization................................................................................212
Active Directory Services Interface ....................................................213
Using ADSI ....................................................................................213
Manipulating Properties ................................................................216
Authenticating Users ......................................................................220
COM+ Security Features ....................................................................222
Declarative Security ......................................................................222
Programmatic Security ..................................................................223
Conclusion ..........................................................................................226
vii
CONTENTS

9 COM+ BUSINESS FEATURES 231


The COM+ Event System....................................................................232
Event Classes..................................................................................233
Event Subscribers ..........................................................................234
Event Publishers ............................................................................237
Filtering Events ..............................................................................238
COM+ Constructors ............................................................................238
Compensating Resource Manager System ..........................................242
CRM Workers ................................................................................242
CRM Clerks....................................................................................243
Compensating Resource Managers ................................................245
CRM Issues ....................................................................................249

10 ASYNCHRONOUS COM+ APPLICATIONS 255


The Microsoft Message Queue............................................................256
MSMQ Applications ............................................................................258
MSMQApplication Object ............................................................258
MSMQQuery Object ......................................................................259
MSMQQueueInfos Object..............................................................260
MSMQQueueInfo Object ..............................................................260
MSMQQueue Object......................................................................261
MSMQEvent Object ......................................................................261
MSMQMessage Object ..................................................................262
MSMQ Limitations ........................................................................264
Queued Components............................................................................265
Designing Queued Components ....................................................266
Calling Queued Components..........................................................268
Using Queued Components in Transactions ..................................271
Exception Classes ..........................................................................272

PART IV USER SERVICES 279

11 COM+ AND THE INTERNET 281


New Internet Information Server Features ..........................................282
Isolating Internet Applications ......................................................282
Generating Custom Error Messages ..............................................285
Using Scriptless ASP......................................................................290
Creating Transactional Web Pages ......................................................290
Understanding Transactional Attributes ........................................290
Creating Multi-Page Transactions ..................................................292
Creating Classes in Scripts ............................................................294
viii
SCOT HILLIER’S COM+ PROGRAMMING WITH VISUAL BASIC

Accessing ASP Objects with COM+ Components..............................298


Understanding XSL Style Sheets ........................................................300
XSL Fundamentals ........................................................................300
XSL Templates ..............................................................................302
XSL Elements ................................................................................305

12 COM+ AND WIN32 311


Maintaining Application State ............................................................312
Custom Collections ........................................................................314
Data Binding ..................................................................................315
User Interface Strategies......................................................................319
ActiveX Controls............................................................................319
HTA Pages ......................................................................................324

13 INTEGRATING COM+ WITH GROUPWARE 331


Integrating Exchange 2000 Server with COM+..................................332
Understanding Web Storage ..........................................................332
ActiveX Data Objects: Accessing Web Stores ..............................334
Collaboration Data: Using Contact and Message Objects ............336
Integrating Microsoft Outlook 2000 with COM+ ..............................338
The Outlook Design Environment ................................................340
Coding Outlook Items ....................................................................343
Integrating Digital Dashboards with COM+ ......................................348

14 DEBUGGING AND DEPLOYING COM+ APPLICATIONS 353


Debugging COM+ Components ..........................................................354
Debugging in Visual Basic ............................................................354
Debugging in Visual InterDev ........................................................355
Deploying COM+ Applications ..........................................................356
Deploying Data Services ................................................................357
Deploying Business Services ........................................................357
Deploying User Services ................................................................359
Deployment Checklist ....................................................................362
Analyzing COM+ Applications ..........................................................363
The Testing Process........................................................................364
Assessing Performance ..................................................................366
Load Balancing ..............................................................................367

15 COM+ CATALOG ADMINISTRATION 377


The COM+ Administration Object Model ..........................................378
The COMAdminCatalog Object ....................................................378
The COMAdminCatalogCollection Object................................380
The COMAdminCatalogObject Object ........................................382
ix
CONTENTS

Performing COM+ Administration with the Windows


Scripting Host....................................................................................383
The WScript Object........................................................................384
The Shell Object ............................................................................385

PART V PUBSONLINE.COM 389

16 DESIGNING THE PUBSONLINE.COM APPLICATION 391


Problem Statement ..............................................................................392
Gathering Requirements ......................................................................392
Membership and Personalization ..................................................393
Promotions......................................................................................393
Analysis ..........................................................................................393
Identifying Actors and Use Cases........................................................393
Log In ............................................................................................394
Add Book to Cart ..........................................................................397
View Cart........................................................................................399
Checkout ........................................................................................401
Screen Shots and the Paper Prototype ................................................403
Data Model ..........................................................................................407
System Models ....................................................................................408
The Three-Tier Model ....................................................................408
Log In ............................................................................................410
Add Book to Cart ..........................................................................412
Check Out ......................................................................................414
Defining Components ..........................................................................415

17 BUILDING THE PUBSONLINE.COM APPLICATION 417


Development Environment ..................................................................418
Creating the Database ..........................................................................419
Creating the COM+ Components ........................................................425
Data Services ..................................................................................428
Business Services ..........................................................................436
Deploying Components ..................................................................440
Creating the Web Interface ..................................................................445

Index 449
About the Author
Scot Hillier is the director of technical staff for DataLan Corporation. With offices in White
Plains and New York City, DataLan offers broad expertise in strategic consulting, networking,
communications, IT security, network management, line of business solutions, and knowledge
management solutions. Scot has written several books, including MTS Programming with
Visual Basic (Sams Publishing) and Inside Microsoft Visual Basic Scripting Edition (Microsoft
Press). In addition to writing, Scot is a regular speaker at industry events such as VBITS and
Developer Days. Scot can be reached at shillier@datalan.com.
Dedication
Illegitimi non Carborundum

Acknowledgments
Only an overdue software project can make you appreciate people as much as writing a book.
In the same way that great software requires a great team, creating a book is the work of many
people. I am always amazed that my name gets prominently displayed when I am but a part of
the effort.
I would first like to thank Sharon Cox, my acquisitions editor. Sharon has been the “go-to”
person for both of my books with Sams. She has not only ensured the success of the process,
but also has been exceedingly patient with me. Through contracts and politics, she kept her eye
on just one thing—producing a quality book. Thank you.
Susan Dunn, my development editor, is the embodiment of professional publishing. While jug-
gling many different books, she kept me focused and provided excellent input.
Rhonda Tinch-Mize was the copy editor who meticulously corrected my misuse of passive
voice, commas, dashes, and capitalized words. Without her, the book would be far less read-
able. Paul Schneider was the project editor. I would like to give a special mention to Rick
Anderson, the technical editor, who was forced to work every exercise in the book. Thank you
to the team.
As I get older, I learn to appreciate my wife, Nancy, more and more. This past year was cer-
tainly turbulent for our family. Nancy began a job as an elementary school teacher after 13
years of raising our children. She now teaches at the school where our kids, Ashley and
Matthew, are students. In fact, she is our daughter’s sixth-grade teacher. As for myself, I
changed jobs after five years, and in the middle of it all was the book. Thank you, family, for
your support and understanding throughout everything.
Many more friends and family members regularly give advise and companionship. I am truly
blessed to know people whose compassion is independent of my success, failure, disagree-
ments, or hardships. The true ones are always there. Thanks again to everyone.
Tell Us What You Think!
As the reader of this book, you are our most important critic and commentator. We value your
opinion and want to know what we’re doing right, what we could do better, what areas you’d
like to see us publish in, and any other words of wisdom you’re willing to pass our way.
As an Associate Publisher for Sams, I welcome your comments. You can fax, email, or write
me directly to let me know what you did or didn’t like about this book—as well as what we
can do to make our books stronger.
Please note that I cannot help you with technical problems related to the topic of this book,
and that due to the high volume of mail I receive, I might not be able to reply to every mes-
sage.
When you write, please be sure to include this book’s title and author as well as your name
and phone or fax number. I will carefully review your comments and share them with the
author and editors who worked on the book.
Fax: (317) 581-4770
Email: adv_prog@mcp.com
Mail: Bradley L. Jones, Associate Publisher
Sams Publishing
201 West 103rd Street
Indianapolis, IN 46290 USA
Introduction
Several years ago, when I was working on my second or third book, I asked a colleague,
“What do developers want from a book?” He responded simply, “Code they can steal.” This
advice has been a guiding principle for me in the creation of this book. This book is designed
to get you started quickly creating business applications with COM+. The book isn’t intended
to cover more theory than is necessary to start solving business problems.
The primary audience for the book is the intermediate developer with a working knowledge of
ActiveX components. This isn’t to say that beginners or advanced programmers won’t benefit
from the content, but the ideal reader has struggled with Windows DNA architecture and is
ready for some guidance. These readers should find plenty of code they can steal.
This book assumes that you have a significant mastery of several key technologies. You should
have a strong background in Visual Basic object principles. You should be able to create class
modules with property procedures and methods compiled into a dynamic link library (DLL).
You should also have a strong understanding of Visual InterDev for creating Active Server
Pages (ASP) applications.
Throughout the book, I develop a repeatable architecture for creating COM+ applications. This
isn’t to say that mine is the only way to create COM+ applications. I have no doubt that some
people will disagree, even vigorously, with the architecture described here. However, I like to
think of this book as a contribution to the discussion of architecture based on Windows DNA
2000. If you follow the guidelines presented here, your application will work.
In the end, I hope you will find the material presented here to help you create better business
applications.

How This Book Is Organized


If you’ve read MTS Programming with Visual Basic, you will find the format and presentation
of this book to be familiar. Each chapter contains a narrative explanation sprinkled with
“Quick Checks”—short exercises—to drive home a lesson. At the end of most chapters, you
will find a complete exercise designed to bring many elements together.

Part I: Understanding COM+ Applications


The four chapters in Part I introduce you to the fundamental concepts necessary to understand
Windows DNA applications and COM+:
• Chapter 1, “Windows DNA and COM+,” introduces you to Windows DNA and COM+
services. In an overview of tiered applications, you’ll learn the fundamentals of partition-
ing and the advantages of creating COM+ applications. You’ll also receive guidance for
creating an appropriate test bed. This section helps you prepare for the exercises used
throughout the rest of the book.
2
SCOT HILLIER’S COM+ PROGRAMMING WITH VISUAL BASIC

• Chapter 2, “Administering COM+,” explains all the administrative tasks associated with
COM+. You’ll get an overview of all the available attributes for computers, applications,
and components. You’ll see how to administer computers that run COM+. You’ll also learn
how to take advantage of COM+ features at the application level. Administrative security
information is presented to help you prevent unauthorized changes to your COM+ applica-
tions. Finally, this chapter details component attributes, to help you take advantage of
resource and transaction management features for the components you create.
• Chapter 3, “Designing COM+ Applications,” explains the design process for COM+
applications from problem statement to deployed application. You’ll learn about a
methodology based on the Rational Unified Process that helps properly define COM+
applications. This methodology provides tangible outputs that you can use to success-
fully create applications. This chapter also presents an overview of the Unified Modeling
Language (UML), which is used in later chapters to design COM+ applications.
• Chapter 4, “COM+ Application Fundamentals,” presents the fundamental concepts
behind COM+. This information forms the foundation for future chapters on specific fea-
tures. You’ll learn the concept of a context, the fundamental container for a component
under COM+. The context helps manage resources and transactions. This chapter also
presents fundamental issues such as object activation and state management. You’ll see
why building COM+ applications requires a thought process different from typical Visual
Basic applications.

Part II: Data Services


The three chapters in Part II detail the construction of a data services layer for your COM+
applications. You’ll learn proven data techniques to create transactional systems that scale.
• Chapter 5, “Accessing Data with COM+,” presents the fundamentals of data access with
COM+ components. It focuses on the use of ADO for data access, as well as on database
connection pooling. The latter feature speeds data access by maintaining a pool of connec-
tions that can be reused. Also, COM+ applications require that data be transported between
various components. This chapter explains how to move data between COM+ components
efficiently. You’ll see several different options for creating and presenting data sets.
• Chapter 6, “COM+ Data Components,” focuses on creating components specifically for
data services. You’ll read about parameter passing and query encapsulation. You’ll learn
to decouple the data access process from the business rules, as well as how to handle
errors that occur during data access. This chapter also explains polymorphic interfaces
within the context of data access. You’ll see how to use interfaces to simplify data access
components and improve maintainability.
• Chapter 7, “COM+ Transactions,” shows how to create, manage, and monitor transac-
tions within your COM+ application. You’ll find out how the Distributed Transaction
Coordinator (DTC) provides strong transactional control and how to access it from
3
INTRODUCTION

COM+. You’ll also see how transactional contexts allow your COM+ components to vote
for the success or failure of a pending transaction.

Part III: Business Services


The three chapters in Part III describe how to construct a middle tier for your COM+ applications.
These chapters will help you secure your system and take advantage of new COM+ features:
• Chapter 8, “COM+ Security,” addresses security for your COM+ applications and com-
ponents. The Active Directory is the central security and profile database for application
users. You’ll see how to use it to log users in to an application and then personalize the
application for individual users. You’ll also learn about COM+’s role-based and program-
matic security features, which allow you to limit access to the functions within a COM+
component.
• Chapter 9, “COM+ Business Features,” presents several new features of COM+ that
weren’t available in the Microsoft Transaction Server. For example, loosely coupled
events allow your COM+ components to send event messages to other components. This
system allows for greater flexibility and maintainability in you applications. Then there
are constructors, special strings sent into a COM+ component when it’s activated.
Constructors can be used to customize the behavior of any component. Finally,
Compensating Resource Managers allow you to create components that can participate in
transactions involving resources other than a database. This feature extends the transac-
tional capabilities of COM+ to resources such as flat files.
• Chapter 10, “Asynchronous COM+ Applications,” focuses on creating applications that
perform work asynchronously. This allows you to build applications that process infor-
mation as a batch. You’ll learn the fundamentals of the Microsoft Message Queue
(MSMQ) and how to use it to set up asynchronous processing. Queued components are a
new feature of COM+. Based on MSMQ, these components provide a simpler mecha-
nism for integrating asynchronous applications into COM+.

Part IV: User Services


The five chapters in Part IV help you to create both Internet and rich client front ends for your
COM+ applications. You also will learn to improve the performance of your applications and
deploy them easily to end users.
• Chapter 11, “COM+ and the Internet,” focuses on features, services, and techniques that
are particular to Internet development. Internet Information Server 5.0 provides several
new features important to COM+ developers. You’ll learn the new security and isolation
features available to your application. You’ll also learn about the new features of Active
Server Pages and how to create transactional Web pages that use script to take advantage
of COM+ features.
4
SCOT HILLIER’S COM+ PROGRAMMING WITH VISUAL BASIC

• Chapter 12, “COM+ and Win32,” presents information necessary to create rich client
front ends for COM+ applications. Maintaining state in COM+ applications requires
thought and planning. This chapter will show you basic strategies for using the client
resources to efficiently maintain application state. However, Visual Basic forms aren’t
the only choice for rich client interfaces. This chapter also will explain several alterna-
tives to forms that are easier to maintain, but still provide full-featured user interfaces.
• Chapter 13, “Integrating COM+ with Groupware,” focuses on using COM+ with the pro-
grammatic features of Microsoft Exchange 2000 and Outlook 2000. You can use
Microsoft Exchange 2000 to create full-featured collaborative applications from COM+.
This chapter will explain how to access the new Web storage facility with the
Collaboration Data Objects. Outlook 2000 provides a simple way to create collaborative
applications for the enterprise. In this chapter, you’ll learn some simple ways to create
collaborative applications using the existing features of Outlook 2000.
• Chapter 14, “Debugging and Deploying COM+ Applications,” investigates the issues
surrounding deployment and performance analysis for your applications. Because quanti-
fying performance has historically been difficult, you’ll learn how to use the Web
Application Stress Tool to verify the performance of your COM+ application. Windows
2000 offers a new way to deploy COM+ applications by using the Windows Installer and
group policies. Together these technologies allow network administrators to deploy
applications to many desktops from a single server location.
• Chapter 15, “COM+ Catalog Administration,” focuses on using the programmatic inter-
face of COM+ services to easily create automated administration tools. In a discussion
on the COM+ Catalog Administration object model, you’ll discover how to automate
tasks such as application creation and component installation. This chapter also covers
the Windows Scripting Host, about which you’ll learn the fundamentals of creating
scripts to automate COM+ administration.

Part V: PubsOnLine.com
In these last two chapters, you put all that you learned in the previous chapters to work by
developing the PubsOnLine.com application. The completed application simulates an
e-commerce bookstore that uses a shopping cart to gather and purchase books. This application
is intended as a complete learning application that uses many of the features presented in the
book.
• Chapter 16, “Designing the PubsOnLine.com Application,” presents the design documen-
tation for the application built in the next chapter. It also presents the application devel-
opment lifecycle you should follow.
5
INTRODUCTION

• Chapter 17, “Building the PubsOnLine.com Application,” presents the actual code for the
project designed in Chapter 16. After completing this chapter, you will have a working
example that can be used as a pattern for your own COM+ development efforts.

Conventions Used in This Book


The following typographic conventions are used in this book:
• Code lines, commands, statements, variables, and any text you type or see onscreen
appears in a monospace typeface. Bold monospace typeface represents what you need to
type.
• Placeholders in syntax descriptions appear in an italic monospace typeface. Replace
the placeholder with the actual filename, parameter, or whatever element it represents.
• Also in syntax, bracketed information, such as [Step IncrementVal], represents
optional settings or values that you can include in your code if your program requires it.
• Italics highlight technical terms when they’re being defined.
• The ➥ icon is used before a line of code that is really a continuation of the preceding
line. Sometimes a line of code is too long to fit as a single line on the page. If you see ➥
before a line of code, remember that it’s part of the line immediately above it.
In addition to typographical conventions, the following special elements are used to set off var-
ious pieces of information and to make them easily recognizable:

NOTE
Special notes augment the material you are reading in each chapter. They clarify con-
cepts and procedures.

TIP
You’ll find numerous tips that offer solutions to common problems as well as short-
cuts.

CAUTION
These warn you about pitfalls and other serious problems that might occur. Reading
them will help you save time and trouble.
6
SCOT HILLIER’S COM+ PROGRAMMING WITH VISUAL BASIC

Key Principle
These call out critical design concepts or implementation concerns that must be
observed. Observing them will help you create better applications.
PART
Understanding COM+
Applications
I
IN THIS PART
1 Windows DNA and COM+ 9

2 Administering COM+ 27

3 Designing COM+ Applications 53

4 COM+ Application Fundamentals 83


Windows DNA and COM+ CHAPTER

1
IN THIS CHAPTER
• Windows 2000 Services 11

• Tiered Architecture Overview 18

• Establishing a Test Environment 23


Understanding COM+ Applications
10
PART I

The Windows Distributed interNet Application 2000 (Windows DNA 2000) platform is
Microsoft’s vision for creating scalable, maintainable, reliable Web-based applications.
Throughout this book, I will examine various aspects of this vision, identify what parts are
strong and what parts are weak. In the end, I will develop a complete methodology and archi-
tecture based on the Windows DNA concept that you can use to create your own e-commerce,
business-to-business, and intranet applications. If you are already familiar with Windows DNA,
you might want to skip this discussion. If you’ve never built a distributed application before,
take the time to read this overview.

NOTE
This chapter functions as an overview of new principles as well as a review of key
concepts. Because subsequent chapters won’t spend time on these fundamental con-
cepts, readers who are weak in these areas should consult other references before
beginning this text.

Like many terms in the Microsoft lexicon, Windows DNA seems to change meaning from time
to time. I’ve heard Microsoft personnel refer to Windows DNA as a tiered architecture as well
as a set of services designed to support a tiered architecture. At one point, I even witnessed a
presentation in which Microsoft personnel suggested that the term DNA was synonymous with
Visual Studio. That would make Windows DNA an architecture, a set of services, and a set of
development tools! It’s no wonder developers are often confused by the messages that come
out of Redmond.
With all these definitions in mind, I will define Windows DNA for the purposes of this book. I
am partial to thinking of Windows DNA solely as a tiered architecture. To us, Windows DNA
is a vision of creating tiered applications that result in outstanding performance. To support the
creation of this architecture, Microsoft has provided a set of services we can take advantage of,
and a set of tools to use when we construct our architecture. Before we begin, I should discuss
the services and tools that live under the Windows DNA umbrella.

What About Microsoft.NET?


As this book was going to print, Microsoft announced a new initiative named
Microsoft.NET. By the time you read this book, you will already be inundated with
information about the .NET initiative, however, that information might leave you
confused about the role of COM+ in future development. Here, I’ll explain the posi-
tioning of .NET relative to COM+ as it’s currently being defined. Keep in mind, how-
ever, that no software was generally available for the .NET platform at the time of
this writing. Therefore, the standard caveat applies: This could all change.
Windows DNA and COM+
11
CHAPTER 1

Microsoft.NET is intended to be a framework that allows developers to create Web- 1


based applications that integrate different Internet services regardless of the plat-

WINDOWS DNA
AND COM+
form or language used by the services. From this perspective, the .NET framework is
separate from COM+ because COM+ is specific to the Windows 2000 platform,
whereas the .NET framework is platform independent.
Perhaps the best way to understand the positioning of a .NET solution is to compare
it to a Windows DNA solution. Windows DNA 2000 is the framework used to create
three-tier applications targeting the Microsoft Windows 2000 platform.
Windows.NET, on the other hand, unifies services on all platforms. This allows, for
example, an application written in Visual Basic running on Windows 2000 to call a
service across the Internet that was written in Java and runs on a Sun platform. This
interoperability is accomplished through the extensive use of the Extensible Markup
Language (XML) to facilitate cross-platform communication.
The question you might ask is, Does this mean that COM+ is no longer relevant? The
answer, of course, is no. COM+ is still a vital part of creating solutions for the
Windows 2000 platform. However, it’s not now nor never was intended to be a cross-
platform technology. Instead, you will use elements of the .NET framework to allow
your COM+ applications to communicate with non-Microsoft services. Therefore, you
will find the information in this book both relevant and useful as Microsoft begins to
release tools for the .NET framework.

Windows 2000 Services


Windows 2000 is the operating system that makes cutting-edge Windows DNA applications
possible. Windows DNA, of course, didn’t originate with the release of Windows 2000; how-
ever, this new OS brings many strong features to the table. These new features form the set of
services that we will use to create our Windows DNA applications. These services are pack-
aged under several different versions of Windows 2000 including the Data Center Server,
Advanced Server, Standard Server, and Professional Workstation.

NOTE
Microsoft often refers to DNA services in Windows 2000 as Windows DNA 2000. The
“2000” label is used to distinguish the set of tools and services from those available
under Windows NT. In this book, I simply refer to all Microsoft-based tiered architec-
ture as Windows DNA.
Understanding COM+ Applications
12
PART I

Active Directory
One of the most significant new features of Windows 2000 is support for the Active Directory,
a Lightweight Directory Access Protocol (LDAP) service that functions as a replacement for
the old Windows Security Accounts Manager (SAM). This means that network administrators
will now use the Active Directory to manage all users, groups, and computers on the enter-
prise. However, Active Directory is much more than just a replacement for the SAM.
Active Directory is essentially a high-performance database optimized for read access. This
database contains not only information about users, groups, and computers, but also tracks vir-
tually any resource on the enterprise. Active Directory can be used to catalog enterprise print-
ers, files, and other resources that can then be searched by clients. This means that users can
search for a specific resource such as a color printer in the same building that uses legal sized
paper.
Active Directory also keeps track of specific user information. The profiles kept in the direc-
tory can include a wide variety of information from email addresses to your boss’s name.
This information can then be published on the enterprise like a network yellow pages. Also,
e-commerce sites can use Active Directory to store information about customers and then
return it later to personalize the Web site.
For users within the domain, Active Directory also serves as a single point of authentication.
Active Directory can not only authenticate users when they log on in the morning, but it can
also authenticate them before they access their email accounts on Microsoft Exchange or
request pages from the corporate intranet. All of this is designed to make the network adminis-
trator’s life easier.
Developers should always create software with Active Directory in mind when targeting the
Windows 2000 platform. Users have come to expect a significant degree of personalization.
Developers should use Active Directory to personalize applications whether they are e-
commerce, intranet, or even Win32 applications. Developers should also use Active Directory
as their sole security mechanism. No one should ever again create a custom security system
consisting of tables in a database. Active Directory already has the infrastructure complete.
Figure 1.1 shows a simple home page giving a personal welcome. I discuss Active Directory in
more detail in Chapter 8, “COM+ Security.”

Internet Information Server 5.0


Internet Information Server (IIS) is in its fifth release under Windows 2000. Microsoft has
added enhancements to the security, performance, and administrative features of IIS to more
fully support Windows DNA applications. This version also contains a number of enhance-
ments for developers utilizing ASP and client-side scripting. These new features are covered in
Chapter 11, “COM+ and the Internet.”
Windows DNA and COM+
13
CHAPTER 1

WINDOWS DNA
AND COM+
FIGURE 1.1
Active Directory contains profile information about users that can be used to welcome them by name to a Web site.

For managing IIS, you can still use the familiar MMC application that was introduced with
version 4.0. However, Windows 2000 provides an enhanced Microsoft Management Console
(MMC) application that shows many of the key services in one location. This applet can be
found on the Start menu under Computer Management. Figure 1.2 shows the new MMC applet
for service management.

FIGURE 1.2
Most of the key services are accessible through the Computer Management console.
Understanding COM+ Applications
14
PART I

Message Queuing
Message queuing is a technology that was introduced with the Windows NT 4.0 Option Pack.
Message queuing is a service that allows developers to create asynchronous communications
between components. The Microsoft Message Queue (MSMQ) service allows a component to
leave a “message” in a queue and then immediately return processing to the calling client. The
message can then be picked up by another component and processed asynchronously. The pro-
cessing component can leave a success or failure message in a outgoing queue for the original
component.
Message queuing is critical to enhancing the performance of distributed systems because it
frees calling clients from waiting for synchronous processes to finish. I have witnessed several
examples of poor Web site design in which scripted pages actually timed out while waiting for
a long process to complete. This often occurs because processes run quickly when developed
on a single machine, but perform poorly when they are deployed. Asynchronous processing is
often the answer. Message queuing is discussed in detail in Chapter 10, “Asynchronous COM+
Applications.”

Universal Data Access


Universal Data Access (UDA) is the Microsoft acronym for technology embodied in OLEDB.
OLEDB is the specification that defines the functionality of the data access objects found in
the ActiveX Data Objects (ADO). The version of ADO released with Windows 2000 is ADO
2.5. ADO 2.5 has several enhancements, but the single largest enhancement is the capability to
stream Extensible Markup Language (XML) text. Streaming XML allows developers to create
Windows DNA applications in which specialized data components use ADO 2.5 technology
internally, but return XML Strings externally. Because XML Strings are primitive data, they
don’t require marshaling and can operate across various platforms. This capability is a critical
part of the general architecture developed in this book. Strong knowledge of ADO 2.5 is a
requirement for building Windows DNA applications. Figure 1.3 shows the new ADO 2.5
object model. I’ll discuss the new ADO capabilities where appropriate throughout the book.

XML Support
Along with streaming XML support in ADO 2.5, Windows 2000 ships with version 2.0 of the
XML Document Object Model (DOM). The XML DOM is the Microsoft XML parsing engine.
The DOM allows components that receive streamed XML to parse the XML and locate infor-
mation. This support makes XML a strong solution for the transport of data over distances.
Internet Explorer has innate support for XML and can display it directly. Figure 1.4 shows an
ADO Recordset converted to XML and displayed in the browser. I discuss XML and the DOM
in detail in Chapter 5, “Accessing Data with COM+.”
Windows DNA and COM+
15
CHAPTER 1

Connection
1
Errors Error

WINDOWS DNA
AND COM+
Properties Property

Command
Parameters Parameter
Properties Property

Recordset
Fields Field

Properties Property

Record
Fields Field

Stream

FIGURE 1.3
ADO 2.5 supports several new features and objects.

FIGURE 1.4
Internet Explorer has built-in support for XML.
Understanding COM+ Applications
16
PART I

Network Load Balancing


As the number of users increases on an application, that application must scale gracefully.
Scaling is the process of adding hardware and enhancing software to handle increased numbers
of users. Windows 2000 supports scaling Web-based applications through the use of Network
Load Balancing (NLB). NLB allows several machines on the enterprise to share a single
Internet Protocol (IP) address. The browser requests are then spread among the available
machines to even the load. As demand on the Web site grows, more machines can be added to
the node.

NOTE
Don’t confuse NLB with the Microsoft Cluster Server technology. NLB is primarily
intended to support the scaling of TCP/IP based applications such as Web sites.
Essentially, this is the technology we use to create a Web farm.

NLB is discussed in detail in Chapter 14, “Debugging and Deploying COM+ Applications.”

Component Services
Component Services is the formal name for COM+. These services are designed to support
scaling and maintaining tiered systems built on component technology. In many ways, COM+
is simply the next release of the Microsoft Transaction Server (MTS). If you have built MTS
applications in the past, you will find COM+ applications to be familiar. Because this set of
services is the primary focus of the book, I will spend some additional time examining the spe-
cific services provided by COM+.

Thread Support
Threads are a sequence of execution steps within a component. Individual components can
support one or more execution points operating simultaneously. Such components are known
as multi-threaded components. Before Windows 2000, components could support either the
single-threaded apartment (STA) model or the multi-threaded apartment (MTA) model. With
the advent of Windows 2000 and COM+, components can now support the thread-neutral
apartment (TNA). TNA components are essential to tapping the full feature set of COM+
because they eliminate many of the drawbacks of STA and MTA components.
STA components are confined to executing on just a single thread. This is problematic because
it can result in deadlock situations in which a process holds the only available thread to a com-
ponent thus blocking other processes. MTA components solve the problem of a single thread
by allowing multiple threads to operate within a given component. The problem with STA and
Windows DNA and COM+
17
CHAPTER 1

MTA components, however, is that they suffer from restrictions on just which threads are 1
allowed to run in the component. TNA components solve this problem by supporting any avail-

WINDOWS DNA
able thread at any time.

AND COM+
In all large applications, proper thread management is critical to scalability and performance.
Regardless of the threading model in use, COM+ provides the underlying support to manage
threads for your components. This means that STA, MTA, and TNA components all work with
COM+; however, other COM+ features can be negatively affected by the choice of threading
model.
The most significant consequence of using Visual Basic for COM+ development is that Visual
Basic 6.0 doesn’t support the thread-neutral apartment model. Visual Basic components sup-
port only the STA model. Microsoft has indicated that Visual Basic will support the TNA
model under version 7.0.

Memory Support
Along with threads, COM+ also provides support for managing the memory used for creating
components. In the most efficient case, COM+ provides for pooling instances of objects cre-
ated that might be reused by subsequent client calls. This mechanism of object pooling is
designed to eliminate the overhead involved in object creation.
Object pooling works by taking objects that are released by calling clients and storing them in
a common pool. The objects in this pool can then be retrieved for subsequent client calls with-
out creating a new object instance. Unfortunately, object pooling requires that components
show no thread affinity. For this reason, object pooling requires that components support the
TNA model. Because Visual Basic 6.0 components can’t be created using the TNA model, they
can’t support object pooling.
On the bright side, however, Visual Basic object creation routines are generally highly opti-
mized. For this reason, lack of object pooling features won’t significantly affect your applica-
tion’s overall performance. Having said this, you can bet Microsoft will be trumpeting object
pooling as soon as it’s possible under Visual Basic 7.0.
In the absence of object pooling, COM+ helps manage memory through the use of just-in-time
activation and as-soon-as-possible deactivation. This feature ensures that an object lives for
only the minimum amount of time necessary to process a function call. Effectively managing
the available memory is critical to scaling a distributed application.

Event Support
Of the new component services provided by COM+, event support is one of the most useful to
Visual Basic programmers. COM+ events form a mechanism for enabling one COM+ compo-
nent to receive events fired by another. In and of itself, this might not seem like a new feature.
Understanding COM+ Applications
18
PART I

After all, Visual Basic has supported the Event keyword for some time. COM+ events, how-
ever, are said to be loosely coupled. This means that event receivers (called subscribers) don’t
need specific knowledge of event providers (called publishers). In fact, a COM+ component
can subscribe to any published event at any time. This significantly simplifies application
development as you add new features to a system. COM+ events are covered in Chapter 9,
“COM+ Business Features.”

Transaction Support
COM+ components provide transactional support just like their Microsoft Transaction Server
predecessors. However, COM+ introduces the concept of automatic transactions. Automatic
transactions allow a component to participate in a transaction and vote for the success or fail-
ure of a transaction without any special coding. Automatic transactions are intended to simplify
COM+ programming; however, they don’t always work well with Visual Basic 6.0 compo-
nents. I will present specific recommendations for building transactional components in
Chapter 7, “COM+ Transactions.”

Asynchronous Support
Another of the newest features of COM+ is support for queued components. These inherently
asynchronous components work with MSMQ to process messages stored in a queue. The setup
to support message queuing is built into the COM+ explorer; therefore, you don’t have to
engage in any separate MSMQ programming to create an asynchronous solution. Queued com-
ponents are discussed in Chapter 10.

Security Support
COM+ provides several enhancements to security checking in a distributed application. For
MTS programmers, you will still find the familiar role-based and programmatic programming
models. However, COM+ also introduces new improvements such as authentication services
that can improve you component’s capability to secure access to resources. Security is dis-
cussed in Chapter 8, “COM+ Security.”

State Support
Application state support is provided by the Shared Property Manager (SPM) in COM+. This
is essentially the same feature set available to MTS programmers. In my experience, however,
developers don’t make enough use of this feature for managing system-wide information. I
cover the SPM in Chapter 4, “COM+ Application Fundamentals.”

Tiered Architecture Overview


At this point in the evolution of distributed application development, you might think that
everyone understands the principles behind tiered applications. I find, however, that this archi-
tectural philosophy is slow to penetrate the Visual Basic community. In early 1999, Deb Kurata
Windows DNA and COM+
19
CHAPTER 1

was still teaching fundamental object-oriented programming at the VBITS conferences, and it
1
was still one of the best received talks long after everyone was supposed to have known the

WINDOWS DNA
information cold. With that in mind, I present the fundamentals of tiered architecture. If you

AND COM+
are already familiar with this discussion, you’ll want to move on.

Two-Tier Architecture
Two-tier architecture is the most common and well-understood approach to database applica-
tions. In this model, the display of data is tightly bound to the storage of the data in the data-
base. In most of these applications, the user interface is merely a reflection of the underlying
data structure. Developers will often take a recordset directly from the database and display it
in a table in which it looks exactly the same as it would if you opened the table directly in the
database. Users interact directly with the data for add, edit, update, and delete functionality.
Business rules that perform functions on the data are either built directly into the user interface
or reside in the database through mechanisms such as triggers. Examples of this type of appli-
cation include data-bound controls and, most recently, ASP pages on the Web. If you write all
your data access code directly in your Web pages, you are creating a two-tier application.
Figure 1.5 shows a diagram of a typical two-tier ASP application.

<%SetMyRS
Serer.CreateObject("ADODB.Recordset")
MyRS.Open%>

ASP Pages Internet SQL Server


Information
Server

FIGURE 1.5
Two-tier architecture ties the Web page directly to the database.

In a two-tier application, data access is most often performed through the use of cursors.
Database cursors allow an application to maintain an open connection to the database while
users scroll and manipulate the data. In most two-tiered applications, the database connection
is established when the application is started and is kept open until the application is closed.
When cursors are combined with a constantly available database connection, applications can
handle concurrency issues through the use of record locking. Record locking prevents two
users from simultaneously making changes to the same database record.
Understanding COM+ Applications
20
PART I

Under many Internet applications, cursors have become less of an issue because Internet devel-
opment inherently drives correct use of database connections. For an application to scale prop-
erly, it must be connected to the database only long enough to read and write data. The very
nature of a technology like ASP is that it can’t support connections to the database for any
longer than a single page. Therefore, the connection must be made and broken each time a new
page is generated.
The exception to this rule is when a developer uses an Application or Session variable to hold a
database connection. These ASP objects allow stateful information to exist between page calls.
Although I see very little of this architecture, you should be keenly aware that using
Application and Session variables—particularly to maintain database connections—can destroy
your application’s scalability and performance. Distributed programming requires accessing
resources only when absolutely necessary.
Another hallmark of two-tiered applications is the use of SQL statements directly in the appli-
cation code or calls to stored procedures directly from the application code. In this design, the
front end requires an intimate knowledge of the database structure and available stored proce-
dures. If the database structure is changed or the stored procedure is altered, it will undoubt-
edly require maintenance on the front end.
Two-tiered applications are generally simpler to design and build than multi-tier applications.
However, simplicity doesn’t come without a price. The tight binding between the database and
the user interface almost always results in an unsatisfying design. Developers are often content
to display database information in tables and lists without much care for the end-user experi-
ence. This mentality reaches its pinnacle when developers dump thousands of records into a
single Web page of search results and declare their job complete simply because the data is
now visible. Users are then left to fend for themselves as they wade through thousands of
records searching for the data they really need.
Another significant disadvantage of two-tier applications is that they are difficult to maintain.
As I’ve pointed out, tight binding between the application and the database means that changes
to either tier can have a disastrous effect on the other tier. This means that new versions of a
product quite often require a complete rewrite of the application. I’ve seen the impact of this
design regularly in the creation of ASP Web sites. Many of these sites have a tremendous
amount of code directly in the page. This disastrous mix of business rules and presentation
information makes for a maintenance nightmare. Often developers can be seen scrolling end-
lessly back and forth in an ASP page searching for a small snippet of code they need to fix.
Does your Web site look like the page shown in Figure 1.6?
All this discussion is not to say that two-tier applications have no place in the new order of
applications. Sometimes when you just want an HTML form to send some email, a quick little
Windows DNA and COM+
21
CHAPTER 1

ASP page is just what you need. The decision to create a two-tier application should be based 1
on the business objectives of the software. You must often balance issues such as time to

WINDOWS DNA
develop against system maintainability and overall cost.

AND COM+
FIGURE 1.6
Two-tier architecture often results in unmaintainable code.

Three-Tier Architecture
Three-tier architecture represents an improvement over the disadvantages of two-tier architec-
ture. In this architecture, the database is separated from the user interface by an intermediate
layer known as business services. This layer eliminates the tight binding between the user
interface (called the user services layer) and the database (called the data devices layer).
Separating user services from data services results in immediate advantages. Because the inter-
mediate layer can process the data before it is displayed, developers can massage the data into
a form that is much easier for the user to work with. Rather than be simply presented in a
table, data can be presented in more meaningful formats. The business services layer makes
this massaging easier to create and maintain. This separation of layers in an application is
referred to as partitioning. Figure 1.7 shows a simple block diagram of a typical three-tier
system.
Understanding COM+ Applications
22
PART I

COM+
Components

XML Pages Internet Information Server SQL Server

User Services Business Services Data Services

FIGURE 1.7
Three-tier architecture often improves scalability and maintainability.

The partitioning of service layers also removes the intimate relationship between SQL state-
ments, stored procedures, and the front-end code. This means that the front end can be changed
more easily without affecting the database, and the database can be altered without rewriting
ASP code. The business services layer also provides a segregated home for the business rules
that work on the data. In this way, the business rules can be changed without affecting the data
or the user interface. This is superior to the use of database triggers that reside directly in the
data services layer.
A separate business services layer also offers an opportunity to construct an application that
shares components in the middle tier. This means that all clients using the application can take
advantage of the functionality provided by the business services. This is a significant advantage
in maintenance because changes to the shared central tier will immediately affect all clients on
the system. This type of design virtually eliminates the need to constantly revise software on
many client machines. It also encourages the reuse of components by fostering a “building
block” approach for applications. These components can participate in one or more applica-
tions simultaneously, making it easier to build and maintain new applications.
Many different technologies are available to create tiered application on Windows 2000. The
choice of which technologies to use depends largely on the application’s objectives. Perhaps
one of the biggest questions you have to answer is whether your application will run in a
browser and if that solution must be supported by both Netscape and Microsoft browsers.
Despite Microsoft’s dominance in the browser market, a significant number of individuals and
companies still rely on the Netscape browser. Because Netscape doesn’t support all the tech-
nologies available to Internet Explorer, we must carefully design our solution with browser
support in mind. Generally, this means returning only HTML to the browser. Technologies like
XML might be used internally in your system, but they can’t be delivered directly to all
browsers that might visit your site.
Windows DNA and COM+
23
CHAPTER 1

Creating a three-tier application is, of course, significantly more complicated than a two-tier 1
application. Right away you have to deal with designing and creating distributed components

WINDOWS DNA
that run remotely. Also, the machines that make up the business services are shared among

AND COM+
many users, so the proper management of these shared resources is critical to the success of
the application. This complexity is the single biggest disadvantage of tiered applications and
the main reason that so few of them are built.
Tiered architecture truly requires a change in the way you understand software systems. The
shift in thought is similar to the change required to move from traditional functional program-
ming to object-oriented (OO) programming. Over the years, when I’ve taught VB developers
OO principles, they’ve had difficulty absorbing the philosophy. However, those who persevere
most often report what I call the “ah-ha” experience. This seems to happen unexpectedly
when, in a sudden flash (usually when the person is involved in a non-programming activity),
OO principles suddenly make sense. I remember clearly a colleague telling me that he had sig-
nificant trouble with OO until one day he was fixing a lawn tractor. As he took apart the
engine, his mind suddenly started describing the pieces as if they were software objects with
properties and methods. He got so excited that he took the tractor completely apart just to
describe each piece as an object.
This experience is often repeated by developers mastering tiered applications. The tiers can be
thought of as “super objects.” Tiers gather objects to form a larger functional block. Much like
the engine is part of the tractor, but the engine is also made up of constituent parts. This idea
of grouping permeates OO systems, and tiered applications are no different. Therefore, the data
services engine can be thought of as a “black box” that delivers data to the system. Internally,
it is made up of components, which in turn are made up of objects. However, just like a good
object, the data services layer doesn’t care what other services call it. Data services just returns
data no matter who calls on it. This idea is expanded and defined throughout the book and con-
stitutes one of the main goals.

Establishing a Test Environment


This book adopts a “blue-collar” approach to Windows DNA applications. This approach, to
me, means an emphasis on building practical solutions—not just discussing theory. To that
end, this book is full of exercises and projects that you can work through to gain a real under-
standing of everyday architectural issues surrounding distributed application design and devel-
opment. Before you begin, you’ll want to establish a test environment where you can easily
work all the projects.
Understanding COM+ Applications
24
PART I

Windows 2000 Advanced Server


Windows 2000 forms the backbone of our test environment. Although you can work with dif-
ferent versions of the operating system at different points in the book, I always assume that
you have the Windows 2000 Advanced Server available. This operating system will allow you
complete access to all the key features from Active Directory to network load balancing.
Installation of the operating system is fairly straightforward with Windows 2000. You can
either upgrade an existing Windows NT platform, create a dual boot system, or boot directly
from the CD-ROM for installation. Throughout the setup, you will find that there are no con-
fusing trouble spots. Just be sure to install the correct services that you will need to run the
exercises in the book as described in the following sections.

Active Directory
When Windows 2000 is first installed, it doesn’t have the Active Directory available. You will
want to install the Active Directory for the server you will use. In some cases, the server you
create might be on a Windows 2000 network already. Under these circumstances, you might
choose to use an existing Active Directory. Note, however, that we will often make changes to
the directory, and you should evaluate the impact before using a live directory. The best bet is
to set up your own server with its own domain separate from any other domain.
Install the Active Directory after you install the operating system. On the Start menu, select
Programs, Administrative Tools, Configure Your Server. This brings up a dialog box that will
allow you to “promote” your server to a domain controller. Figure 1.8 shows the home page of
the configuration utility.

FIGURE 1.8
Set up Active Directory after Windows 2000 is installed.
Windows DNA and COM+
25
CHAPTER 1

During the promotion process, you will be prompted to set up the Domain Name Service 1
(DNS). DNS allows computer names to be resolved to TCP/IP addresses. Active Directory

WINDOWS DNA
requires this service to operate correctly. Although the setup will make appropriate DNS

AND COM+
entries for your promoted server, you might have to make additional entries by hand if you are
working with several Windows 2000 machines on a network. Figure 1.9 shows the typical
server entry for the promoted server. Obviously, this text can’t describe in detail the setup
requirements for all Windows 2000 services, but you should have a good plan before you begin
the installation process.

FIGURE 1.9
Active Directory requires the DNS service.

Internet Information Services


Internet Information Services (IIS) installs automatically with your Windows 2000 Advanced
Server. This book doesn’t require any special configurations for IIS during installation.
However, you should ensure that you are designated with sufficient permissions to administer
your IIS service. Again, it’s best to simply set up a separate domain for completing exercises.

Microsoft Message Queue


MSMQ is required for working with queued components. MSMQ isn’t installed by default;
you must specify that it be installed during the setup process for Windows 2000 Advanced
Server. MSMQ also requires additional setup after the Windows 2000 installation is complete.
Figure 1.10 shows the Windows component dialog for installing MSMQ.
Understanding COM+ Applications
26
PART I

FIGURE 1.10
MSMQ setup must be completed after Windows 2000 is set up.

SQL Server 2000


Many database exercises in this book require SQL Server 7.0 or higher. In many cases, the
book uses the pubs database that ships with SQL Server. You must also be designated as the
administrator for SQL Server, although it is perfectly acceptable to leave unchanged the default
system administrator designation of sa with no password. When this book uses custom SQL
Server databases, you will generally find a batch of SQL files that you can run to set up the
databases. Therefore, you should be familiar with essential SQL Server administrator tasks
such as creating accounts and establishing permissions for database objects.

Visual Studio
Visual Studio, Enterprise Edition, contains all the software necessary to code the exercises in
the book. The exercises are all created in Visual Basic 6.0; however, several other applications
are required to support the projects. In particular, this book relies heavily on Visual InterDev
for Web site construction. This book assumes a strong background in the fundamentals of Web
site development with Visual Studio.
Administering COM+ CHAPTER

2
IN THIS CHAPTER
• The Component Services Explorer 28
Understanding COM+ Applications
28
PART I

The bulk of this book is dedicated to creating solutions—and that means writing code.
However, you can’t create COM+ solutions unless you understand the administrative tasks
associated with installing and maintaining the components. This chapter will give you the
essentials you need to understand the management tools associated with COM+.

The Component Services Explorer


Administering COM+ components is done through the Component Services, or COM+,
explorer. This interface is accessible from the Start menu by selecting Programs,
Administrative Tools, Component Services. If you are familiar with the Microsoft Transaction
Server (MTS) explorer from Windows NT, you will find the COM+ explorer to be similar.
Figure 2.1 shows the Component Services interface.

FIGURE 2.1
COM+ is managed through the Component Services interface.

The Component Services explorer divides COM+ management into a hierarchical structure
with a treeview on the left and listview on the right. The treeview creates a simple hierarchy of
computers, applications, and components. Opening the Component Services node reveals the
Computers folder, which allows access to servers running COM+ components. Opening a com-
puter node reveals the COM+ Applications folder, which groups components into a logical
package. Opening a COM+ application node reveals the Components folder, which allows
Administering COM+
29
CHAPTER 2

access to COM+ features for any component. Together, these three divisions form the core of
Component Services.

Computer Properties
Inside the COM+ explorer, you can access properties for any item by right-clicking and select-
ing Properties. Opening the Properties dialog for My Computer reveals six tabs that help you
manage settings for the computer as a whole.

The General Tab


The first tab in the dialog, General, serves as a place to enter a description of the server. The
2
description can be as long as 500 characters. Figure 2.2 shows the General tab.

ADMINISTERING
COM+
FIGURE 2.2
Enter a server description in the General tab.

The Options Tab


The second tab on My Computer Properties is Options (see Figure 2.3). This tab allows you to
set the global timeout property for transactions managed by COM+. This setting causes trans-
actions to automatically be aborted if they take longer than the designated interval. If you never
want a transaction to timeout, you can set this value to zero; however, a zero value isn’t recom-
mended because a bad transaction could hang the system.

The global timeout is the default for all components in COM+; however, the setting can be
overridden by any individual component. Later in this chapter, we’ll see that each individual
component can set a transaction timeout. This value is normally not set, but must be manually
activated.
Understanding COM+ Applications
30
PART I

FIGURE 2.3
The Options tab.

Along with the transaction timeout, the Options tab allows you to specify an alternate applica-
tion proxy server. The purpose of this setting is to support the installation of remote Win32
client front ends. This is done from the COM+ explorer through a process known as exporting.
When a proxy is exported, COM+ creates a special installation for a remote client front end
that will allow the client to use COM+ components. The issue here is that Win32 clients need
to know the name of the server where the COM+ components can be located. Exporting a
proxy normally points all client software at the server where the export is done. However, if
you want the proxies directed to a different server, you can enter the name of the server in the
Options tab.

The MSDTC Tab


The third tab on My Computer Properties, the MSDTC tab, gives you control over settings for
the Microsoft Distributed Transaction Coordinator (MSDTC). The MSDTC is responsible for
managing distributed transactions in COM+. Distributed transactions enable your COM+ sys-
tems to perform transactions across multiple components and multiple databases. The MSDTC
is discussed in detail in Chapter 7, “COM+ Transactions.” Figure 2.4 shows the MSDTC tab.

The Default Properties Tab


The Default Properties tab in My Computer Properties allows you to set properties for
Distributed COM (DCOM). DCOM services, enabled by default when you set up Windows
2000, form the backbone of any distributed system. These services enable applications on one
computer to call the COM+ components on another computer. If you disable DCOM services,
you can run your COM+ applications only on a single machine. This essentially defeats the
purpose of COM+.
Administering COM+
31
CHAPTER 2

ADMINISTERING
COM+
FIGURE 2.4
The MSDTC tab.

When DCOM is enabled for the server, you can set the Default Authentication Level and the
Default Impersonation Level for the server. The Default Authentication Level setting deter-
mines when a caller’s identity is authenticated. Just as you must be authenticated before being
logged on to a network, COM+ will authenticate users who are attempting to access the ser-
vices of a distributed component. The authentication level settings enable authentication at var-
ious levels based on how tightly you want to control security. Table 2.1 lists the available
settings and explains their effect.

TABLE 2.1 DCOM Authentication Levels


Setting Explanation
Default Use the default security settings for the application.
None No authentication is performed.
Connect Callers are authenticated only when they first connect to a
component.
Call Callers are authenticated each time they access a method of a
component.
Packet Each data packet is authenticated.
Packet Integrity Authenticates each packet and ensures that no packet data has been
modified during transmission.
Packet Privacy Authenticates each packet, ensures that no packet data has been
modified during transmission, and encrypts the data.
Understanding COM+ Applications
32
PART I

Impersonation is a process that allows a component to assume the permissions of a Windows


2000 user for the purpose of accessing system resources. The Default Properties tab provides a
number of different settings that affect the capability of a component to access the system.
Table 2.2 lists the settings and their features.

TABLE 2.2 Impersonation Level Settings


Setting Explanation
Anonymous The caller can’t be identified.
Identify The component can impersonate the caller for identification pur-
poses only.
Impersonate The component can impersonate the caller to access system
resources.
Delegate The component can impersonate the caller to gain access to system
resources and to make calls to other objects.

Although the DCOM subsystem is essential for creating distributed applications, it can have
limitations when you want to distribute the system across the Internet. DCOM can run over
HTTP protocol; however, DCOM requires the use of many different ports to successfully com-
municate in a range of 1024-65535. Typically, firewalls and proxy servers block the ports that
DCOM requires, which effectively prevents DCOM from functioning over the Internet. To
overcome this problem, you can enable COM Internet Service on the Default Properties tab.
When COM Internet Services are enabled (see Figure 2.5), COM+ components use port 80 to
perform an initial handshake that establishes connectivity through a firewall or proxy server.
This allows you to create true distributed applications that work across the Internet. COM
Internet Services require the use of a special moniker called OBJREF that allows a browser to
locate a running component on a Web server.

The Default Security Tab


The Default Security tab allows you to set default access and launch permission for COM
applications running on this server. The important distinction here is that these settings have no
effect on COM+ applications—they affect only COM applications. Figure 2.6 shows the
Default Security tab.

The Default Protocols Tab


The final tab on My Computer Properties is Default Protocols. This tab specifies the protocols
available to the DCOM subsystem. The order that they are listed affects the order in which
they are used. Figure 2.7 shows the Default Protocols tab.
Administering COM+
33
CHAPTER 2

ADMINISTERING
COM+
FIGURE 2.5
The Default Properties tab.

FIGURE 2.6
The Default Security tab.

My Computer Tasks
Along with access to the properties of My Computer, the Action menu also allows you to per-
form two other useful tasks: managing the MSDTC service and refreshing COM+ components.
From the Action menu, you can start and stop the MSDTC. Starting and stopping this service
can actually be done from a number of places, including the MSDTC tab and the Services
Understanding COM+ Applications
34
PART I

node found at the bottom of the COM+ explorer. Refreshing COM+ components is useful any
time you install a new version of a DLL into COM+. This is common during development, but
also happens when new versions are rolled out.

FIGURE 2.7
The Default Protocols tab.

Application Properties
COM+ components are grouped under a server into COM+ applications. The term application
is somewhat misleading when used in this context because developers might tend to think of
executable content. However, the truth is that a COM+ application is a grouping of components
for administrative and security purposes. The COM+ application is similar to the “package”
under MTS.
Along with security and administration features, each COM+ application is associated with a
running instance of the executable dllhost.exe. This executable provides a runtime environ-
ment for COM+ components, which allows COM+ to provide services. This one-to-one map-
ping between COM+ applications and dllhost.exe is a critical architectural point that will
affect your system design significantly as you proceed through the book.

The General Tab


As with My Computer, you can access the properties for any COM+ application by right-
clicking and selecting Properties from the pop-up menu. The first tab you will see on the prop-
erty sheet is the General tab, which contains the name and description of the COM+ applica-
tion.
Administering COM+
35
CHAPTER 2

Each COM+ application is also assigned an AppID, a globally unique identifier (GUID) that
identifies the COM+ application. This number is useful when you are performing administra-
tive tasks programmatically. In Chapter 15, “COM+ Catalog Administration,” I discuss pro-
grammatic administration. Figure 2.8 shows the General tab.

ADMINISTERING
COM+
FIGURE 2.8
The General tab.

The Security Tab


The Security tab on the COM+ application property sheet allows you to specify whether access
to the COM+ components in the application will require permission and exactly how the
authentication will occur. For security checking to be active, you must check the Enforce
Access Checks for this Application box. When security is enabled for the application, COM+
uses special “roles” that you define to determine whether access is allowed to the components
in this application. Roles are discussed in Chapter 8, “COM+ Security.”
In the Security Level settings, you can choose to have COM+ perform security checks at the
process or component level. The default is to check at the component level. Checking security
at the component level enables you to find out additional information about calling clients. For
example, you can determine the identity of a calling client programmatically when you check
access at the component level.
The Security tab also allows you to set the Authentication and Impersonation levels for the
application. These settings are the same as the default settings discussed under the My
Computer properties, and will override those settings. Figure 2.9 shows the Security tab.
Understanding COM+ Applications
36
PART I

FIGURE 2.9
The Security tab.

The Identity Tab


The Identity tab on the COM+ application property sheet allows you to set the Windows 2000
user under whom the application will run. On this tab, you may select to run the application as
the Interactive User or under a particular account.
When you specify that a COM+ application should run as the Interactive User, you are stating
that all COM+ components in the application will have the identity and permissions of the per-
son currently logged in to the server where the application is located. This setting is useful if
you are a developer building a COM+ system on a single machine, but has little value in a
final, deployed application. This is because you would actually have to have someone logged
in to the server when the application is deployed. If you log out of the server where the COM+
application is running, the components won’t run and all clients will receive permission errors.
The correct way to set up a COM+ application is to select a specific account to run your com-
ponents. We normally set up an account with just the minimum number of permissions neces-
sary to run the application. You will need just such an account to run several of the applications
in this book. Figure 2.10 shows the Identity tab.

The Activation Tab


The Activation tab on the COM+ application property sheet allows you to specify whether the
COM+ application runs as a server or a library application (see Figure 2.11). Server applica-
tions run in a copy of dllhost.exe, whereas library applications run in the client application’s
memory space.
Administering COM+
37
CHAPTER 2

ADMINISTERING
COM+
FIGURE 2.10
The Identity tab.

FIGURE 2.11
The Activation tab.

The default setting for the Activation tab is to run as a server application. Running within
dllhost.exe enables COM+ to provide full support to the components in the application. It
also enables components to be called from remote clients. Selecting to run as a library applica-
tion, on the other hand, removes all COM+ support, with the exception of role-based security,
because the runtime environment isn’t used. All application support must come from the client
application itself. This setting also implies that the client application must be located on the
same machine as the COM+ components so that they can be loaded into the client memory
space.
Understanding COM+ Applications
38
PART I

Component Services run on clients as well as servers. If you export an application proxy for a
client to use, it will be installed as a COM+ application on the client. When you install an
application proxy, the name of the server where the component is located appears in the
Remote Server Name box.

The Queuing Tab


The Queuing tab on the COM+ application property sheet allows you to designate the compo-
nent as a queued component (see Figure 2.12). Queued components are associated with queues
in the Microsoft Message Queue (MSMQ). Setting the Queued property automatically sets up
special queues for incoming messages to this component. You can then write code to program-
matically examine and process messages in these queues.

FIGURE 2.12
The Queuing tab.

If you don’t want to write the queue processing code yourself, you can further designate that
the component should listen. When a component is set to listen, it will automatically process
messages in its associated queues as they arrive. This means you can establish asynchronous
processing with no code at all. Queued components are covered in detail in Chapter 10,
“Asynchronous COM+ Applications.”

The Advanced Tab


Advanced, the sixth and final tab on the COM+ application property sheet, allows you to con-
trol many aspects of how the COM+ application behaves. The first setting you can affect deter-
mines what happens to your COM+ application when there are no longer any clients calling it.
When your COM+ application is idle, you might choose to leave it running or shut it down
after a period of time. The default is to shut down the application after three minutes to
Administering COM+
39
CHAPTER 2

conserve resources. However, if this application is critical to the performance of your system
or takes a long time to initialize, you might want to leave it running.
After the COM+ application is defined, you might want to disable changes and deletions to the
application. Disabling changes and deletions prevents people not designated as a COM+
administrator from modifying the application. I discuss designating COM+ administrators in
the next section.
The Advanced tab also provides support for launching compiled Visual Basic components in
the C++ debugger. If you want, check the box to launch the specified debugger. The COM+
application has a default entry, but you can change the debugger launch string if you need to. 2

ADMINISTERING
COM+ provides support for automatic transactions that you can use to create transactional sys-

COM+
tems. For many business purposes, database transactions are enough support. However, you
might have another data source that you want involved in a transaction. For these sources, you
might have to create a Compensating Resource Manager (CRM), which provides support for
voting in transactions. Once created, you typically install them in a COM+ application and
then select to enable the CRM. This check box allows the CRM to be used. You can build a
complete CRM in Chapter 9, “COM+ Business Features.”
Finally, the Advanced tab allows you to specify that your COM+ application can access up
to 3GB of memory within Windows 2000. Using this feature requires that you enable access
to 2GB and larger memory blocks within Windows 2000 itself. Figure 2.13 shows the
Advanced tab.

FIGURE 2.13
The Advanced tab.
Understanding COM+ Applications
40
PART I

The System Application


Earlier, I alluded to designating administrators for Component Services. Setting up administra-
tive privileges is accomplished through a special COM+ application called the System
Application. The System Application is a COM+ application that contains the components
which perform administrative tasks in COM+.
When Windows 2000 is first installed, the Component Services explorer is available only to
domain administrators. This is because Component Services places the domain administrators
group under the Administrator role in the System Application. The Administrator role is just
one of five roles defined within the System Application. Table 2.3 lists all the roles to which
users can be assigned.

TABLE 2.3 System Application Roles


Role Permissions
Administrator Modifies configurations and components.
Any Application Contains all usernames utilized for application identity for both
library and server applications.
QC Trusted User Sends messages for queued components on behalf of other users.
Reader Has read-only access to Component Services.
Server Application Contains all usernames utilized for application identity for server
applications only.

Creating Applications
When deploying a system under COM+ services, one of the first tasks you’ll have to perform
is the creation of a new COM+ application. This task is accomplished by clicking the COM+
Applications folder and selecting New/Application from the Action menu. When you select to
create a new application, COM+ starts the COM+ Application Install Wizard, as shown in
Figure 2.14.

This wizard helps you with the basic task of creating a new COM+ application. When you use
the wizard, you can choose to create a new application or import one that was exported from
another Windows 2000 server. Usually, you’ll be creating a new application. Figure 2.15 shows
the screen for choosing to import or create a new application.
Administering COM+
41
CHAPTER 2

ADMINISTERING
COM+
FIGURE 2.14
The new COM+ application Welcome Screen.

FIGURE 2.15
COM+ applications can be created or imported.

The wizard requires only a few pieces of information beginning with a name. In the next step,
you’ll give the application a descriptive name (see Figure 2.16). This name can include white
spaces.

The wizard also prompts you for the identity under which to run the application. As I said ear-
lier, you can use the Interactive User setting for most examples in this book; however, you’ll
want to set up a real account for deployed systems. It’s generally best to have the account set
up ahead of time and entered under the appropriate roles in the System Application. You can,
however, always change these settings later. Figure 2.17 shows the screen for selecting the
application identity.
Understanding COM+ Applications
42
PART I

FIGURE 2.16
COM+ applications are given descriptive names.

FIGURE 2.17
Set the COM+ application identity.

When the wizard is complete, COM+ will make the new application. All the features of COM+
are now available to components you install in the new application. Figure 2.18 shows the final
screen before the new application is created.

Component Properties
COM+ applications are made up of components. Just like computers and applications, compo-
nents have property settings that you can change. To access the property sheet for any compo-
nent, simply right-click the component and select Properties from the pop-up menu. The
property sheet will then appear.
Administering COM+
43
CHAPTER 2

ADMINISTERING
COM+
FIGURE 2.18
Create the new COM+ application.

The General Tab


The first tab on the component property sheet is the General tab (see Figure 2.19). The General
tab contains fundamental information about the component, such as the name, description, par-
ent DLL, class identifier, and application identifier.

FIGURE 2.19
The General tab.

The Transaction Tab


The Transaction tab on the component property sheet allows you to specify the transactional
behavior of the component (see Figure 2.20). The settings found here determine whether a
Understanding COM+ Applications
44
PART I

component can vote in transactions and how it votes when other components are involved.
Chapter 7 covers transactions in detail.

FIGURE 2.20
The Transaction tab.

The Security Tab


The Security tab on the component property sheet is used primarily to allow access to the func-
tionality of the component based on roles (see Figure 2.21). You’ve already seen several roles
associated with the System Application and will learn more about roles in Chapter 8. However,
once a role is defined, you must add it to the Security tab of the component to allow access.

FIGURE 2.21
The Security tab.
Administering COM+
45
CHAPTER 2

The Activation Tab


The Activation tab on the component property sheet is where you would designate that your
component supports object pooling (see Figure 2.22). As we discussed in the previous chapter,
however, object pooling requires support for the thread-neutral apartment (TNA) model,
which Visual Basic 6.0 doesn’t support. Therefore, this option is always unavailable for VB
components.

ADMINISTERING
COM+
FIGURE 2.22
The Activation tab.

One nice feature of COM+ that’s available to Visual Basic components is object construction.
Object construction enables your component to receive a constructor string when it’s first acti-
vated by COM+. This string can be anything. It might be a flag indicating that a generic com-
ponent should behave in a specific way. My favorite use is to provide connection strings and
directory paths so that a data source path can be easily changed.
The Activation tab has the Enable Just-in-Time Activation (JIT) field set by default. This fea-
ture allows COM+ to create and destroy instances of the objects created by the component to
efficiently manage resources. I discuss JIT activation in Chapter 4, “COM+ Application
Fundamentals.”
The Activation tab also allows you to specify that your component should support statistics.
Setting this option means that you can view statistics about the performance of the component
while it’s running. These statistics are available in the listview of the Component Services
explorer for the selected component.
Components can be forced to run in the context of their caller by setting the Must Be Activated
in Caller’s Context flag. All COM+ objects run inside a context. The context—a new feature of
Windows 2000—requires a detailed explanation. I tackle this issue in the next chapter.
Understanding COM+ Applications
46
PART I

The Concurrency Tab


The Concurrency tab on the component property sheet allows you to specify the synchroniza-
tion attribute for your component (see Figure 2.23). Synchronization helps ensure that only a
single thread flows through an object instance at any time. Visual Basic components don’t
require synchronization because they are already single-threaded. However, COM+ might
demand that you set synchronization to support transactions of JIT activation. Concurrency and
synchronization are discussed in Chapter 4.

FIGURE 2.23
The Concurrency tab.

The Advanced Tab


Advanced, the sixth and final tab on the component property sheet, allows you to specify the
class that can handle exceptions that occur when a queued component doesn’t receive a mes-
sage. Normally undelivered messages are sent to the dead-letter queue, but COM+ will attempt
to call the exception class, if specified, before delivering unreceived messages to the dead-letter
queue. Figure 2.24 shows the Advanced tab.

Installing COM+ Components into an Application


After you have created a new COM+ application, you will want to install components in it.
Component installation is accomplished by selecting the Components folder beneath the
COM+ application and choosing New/Component from the Action menu. This will start the
COM Component Install Wizard. Figure 2.25 shows the welcome screen for the wizard.
Administering COM+
47
CHAPTER 2

ADMINISTERING
COM+
FIGURE 2.24
The Advanced tab.

FIGURE 2.25
The new COM+ component Welcome Screen.

Components can be installed in your COM+ application be referencing a DLL, or by examin-


ing the System Registry. Generally, it’s better to reference the DLL when installing COM+
components because COM+ can read the type library (TLB) associated with the DLL to return
interface information. Selecting to read the System Registry is necessary only if you have pre-
viously installed a component from a DLL and now need to add a new class from the same
DLL to a different application.
Understanding COM+ Applications
48
PART I

The wizard also allows you to install event classes. Event classes are the foundation of the new
loosely-coupled event system in COM+. I discuss the event system in Chapter 9, “COM+
Business Features.” Figure 2.26 shows the screen for selecting how to install the components.

FIGURE 2.26
COM+ supports different installation methods.

When you have elected to install from a DLL, you can use the wizard to locate the file. Once
located, the wizard will examine the DLL and identify all class modules within the DLL that
can be added to the COM+ application. Figure 2.27 shows a typical DLL examined by the
wizard.

FIGURE 2.27
Locate the DLL to install.

After you have identified the component to install, the wizard adds the classes to your COM+
application. You can then use the property sheet to set the attributes of the component. Figure
2.28 shows the final screen before the wizard adds the class to the application.
Administering COM+
49
CHAPTER 2

ADMINISTERING
COM+
FIGURE 2.28
Complete the component installation.

EXERCISE 2.1

Creating a Simple COM+ Application


This exercise utilizes the fundamental administrative skills required in COM+. You will create
an application and install components in the application. After you have a component under
COM+ control, you will build a simple front end to call the component.

Step 1
Using the File Explorer, create a new directory called COM+\EXERCISE2-1.

Step 2
Start a new ActiveX DLL project in Visual Basic. I will discuss the exact nature of the relation-
ship between ActiveX components and COM+ later, but for now just recognize that COM+
uses ActiveX DLL components exclusively.

Step 3
Open the project properties dialog by selecting Project1 Properties from the Visual Basic
Project menu. In this dialog, change the name of the project to SimpleObject. While the dia-
log is open, ensure that the threading model for your component is set to Apartment
Threaded. All COM+ components should use apartment threading to allow COM+ to handle
the thread pooling for the component. Close the project properties dialog.
Understanding COM+ Applications
50
PART I

Step 4
Select Class1 in the Project Explorer. Change the name of the class to Simple.

Step 5
Open the code window for class Simple. In the code window, add a new method to the class by
selecting Add Procedure from the Tools menu. Add a new method named Process. Make this
method a Public Function. When you have added the new method, modify the function signa-
ture to return a String data type. The completed function signature is as follows:
Public Function Process() As String
End Function

Step 6
The Process method is a trivial routine designed just to allow you to work with applications
and components. As such, add the following code to the Process function to return a message
to the calling client:
Process = “I got your call!”

Step 7
Compile your ActiveX DLL by selecting Make SIMPLEOBJECT.DLL from the File menu.
When you have completed the compile, save your work and exit Visual Basic.

Step 8
Open the COM+ Explorer. Locate My Computer and expand the treeview until you see the
COM+ Applications folder. Click the folder. Then choose New/Application from the Action
menu to start the Application Wizard.

Step 9
In the first step of the Application Wizard, choose to create an empty application. In the second
step of the Application Wizard, name the new application Simple. In the third step of the
Application Wizard, set the application identity as Interactive User. Click Next and then
Finish to create the application.

Step 10
After the application is created, locate it in the COM+ Explorer. Expand the treeview until you
find the Components folder. Click the folder and select New/Component from the Action
menu to start the Component Wizard.

Step 11
In the first step of the Component Wizard, select to Install New Component(s). In the
second step of the Component Wizard, use the file dialog to search for and locate the file
simpleobject.dll that you created earlier. When you select this file, the object inside the
Administering COM+
51
CHAPTER 2

DLL will be listed in the Add Components dialog. Click Next and then Finish to add the com-
ponent to your application. You are now ready to call the component from Visual Basic.

Step 12
Return to Visual Basic and start a new Standard EXE project. This project will be a front end
to the component in COM+.

Step 13
Open the references dialog for the new project by selecting References from the Project
menu. In the references dialog, set a reference to SimpleObject. Close the references dialog. 2
Step 14

ADMINISTERING
As a simple example of calling a COM+ component, we will just create an instance of the

COM+
SimpleObject component. Double-click Form1 in the Project Explorer. Add a CommandButton
to Form1 from the toolbox. Change the caption on this button to Process.

Step 15
Open the code window for Form1. In the Command1_Click event, add the following code to
create an instance of the SimpleObject component and call the Process method:
‘Create Business Object
Dim objSimple As SimpleObject.Simple
Set objSimple = New SimpleObject.Simple

‘Call Business Object


MsgBox (objSimple.Process)

Step 16
Save your work. Start your Standard EXE project.

Step 17
When you get a response from COM+, leave the MsgBox visible and examine the Simple
object in the COM+ Explorer. You should see the component ball spinning indicating that it is
active. If you close the MsgBox by clicking OK, the animation stops.
Designing COM+ Applications CHAPTER

3
IN THIS CHAPTER
• Assessing Functional Requirements 54

• Describing the System 58

• Creating the Paper Prototype 65


Understanding COM+ Applications
54
PART I

Application design has become a critical topic as the complexity of Windows solutions
increases. Historically, Visual Basic has had the reputation of being a rapid prototyping tool,
which led to a “design as you code” mentality. As systems became larger, however, this men-
tality led to significant problems with scalability and maintainability. This chapter will show
you a proven methodology for creating COM+ applications successfully the first time.
My design solution is a variant of the Rational Unified Process (RUP), which combines many
object-based design methodologies into a whole. RUP encourages both text and graphical mod-
eling of the system before beginning the coding process. In its commercial version, RUP is
also supported by a set of tools available from Rational Software. These tools help create the
models necessary to successfully define a system. I have used, and like to use, many of the
Rational products, but they aren’t required to complete your design. You can easily use other
tools such as Visio or Microsoft Visual Modeler to create your models. In this chapter, I use
only Visual Modeler because it’s available in Microsoft Visual Studio.
This chapter uses small examples to help you understand the concepts presented. However,
Chapter 16, “Designing the PubsOnLine.com Application,” contains a complete project specifi-
cation, which contains all the elements discussed here. Also, Chapter 17, “Building the
PubsOnLine.com Application,” contains the complete code for the project defined in Chapter 16.
These two chapters present a practical application of the process defined here in this chapter.

Assessing Functional Requirements


The design of every system begins by recording exactly what’s to be accomplished. Often pro-
grammers, and even my customers, scoff at the notion of writing everything down. Even now,
many of them believe that a system can be defined verbally in a single meeting. I have been
known to turn down such projects rather than suffer through the agony of shifting require-
ments. The best projects, however, begin with a simple problem statement.

Problem Statement
A problem statement is a paragraph that describes exactly why the system is being created. It
clearly states the project’s objectives and what problem is to be solved. The problem statement
should be free of technical acronyms. State the problem in terms of the business objective, not
the technical objective.
I have occasionally been in meetings in which the customer’s company president makes a
statement such as, “We need a SQL Server database with product information available for our
sales people.” Our response is to ask, “What’s the business objective?” After some wrangling,
we eventually get an answer such as, “We need to increase order fulfillment time by 25%.”
Now we can understand!
Designing COM+ Applications
55
CHAPTER 3

Key Principle
A problem statement focuses on the business problem to be solved, not the technol-
ogy to be used.

The point here is that the SQL Server database might not be the best answer. To give the best
technical solution, we need to understand the business problem to be solved. Too often, devel-
opers have a technology looking for a problem, not the other way around. If a Windows 3.1
solution with Visual Basic 3.0 is the best answer, have the courage to say it. The following
problem statement is an example. This typical problem statement defines the problem to solve
as well as the business objective behind it:
XYZ Books Incorporated has an existing Web site used for selling its books online.
Based on comparisons with other book companies, XYZ Books believes that sales from
the site are below average. XYZ Books wants to increase online sales by 300%.
Given the complexity of creating Windows DNA solutions, the task of creating a problem
statement seems almost trivial. However, even the simplest statement causes the company to
focus. For example, the preceding statement indicates an objective of 300% increase in sales.
3
This statement can’t be made lightly. The exact percentage will have to be approved at a high

APPLICATIONS

DESIGNING
level of management. This will cause discussion among company management that will attract

COM+
attention to the project and sharpen everyone’s focus. One benefit of a good design process is
that it involves the entire organization and demands buy-in from all quarters.

Gathering Requirements
Once the problem statement is written, you are ready to create a list of functional require-
ments. The list of requirements allows you to attain the next level of detail in the design.
Functional requirements are always a group process. In this process, assemble everyone who
has an interest in the project for group meetings.
At any organization, a software development effort will have a single person who acts as an
advocate. This person, whom we call the champion, is the true customer of the developers. The
champion is responsible for securing funding and protecting the project from its enemies. As
you begin to assemble the functional requirements for the system, never lose sight of the true
customer.
Around the champion are many people with an interest in the project. We call these people
stakeholders. A stakeholder is anyone in the organization who could derail or delay the devel-
opment effort. Some stakeholders will be excited about the project and function as secondary
advocates. Some will try to expand the scope of the effort to solve problems not contained in
Understanding COM+ Applications
56
PART I

the problem statement. Finally, some stakeholders will be threatened by the project and try at
every turn to have it cancelled. The point is that a software development effort can’t truly suc-
ceed without the buy-in of every stakeholder at the organization.

Key Principle
To the greatest extent possible, all stakeholders must eventually buy in to the devel-
opment effort.

To identify the functional requirements for the system, work with the champion to identify all
stakeholders. These stakeholders are then invited to a series of meetings to discuss the project
and its requirements. I refer to these meetings as facilitated sessions because a knowledgeable
mediator who can keep the group on track guides the meeting, derives requirements, and
presses for buy-in.
Facilitating a meeting of stakeholders can be dicey at best. In these meetings, you will have
both advocates and enemies. The mediator must be skilled and experienced at handling such
groups. There’s no formula for how to handle a group of stakeholders, but my experience is
that these meetings often clear the way for a successful project.
In the facilitated session, begin by introducing all the stakeholders and explaining to them the
purpose of the meeting and the process we will follow. The idea here is to immediately set
ground rules to keep the project enemies from openly criticizing the project as a whole. The
facilitator must be seen as controlling the meeting. If the session turns into a free-for-all, the
project enemies will make the meeting unproductive.
After the format and rules are explained, invite the stakeholders to state the functions they want
to see in the system. Furthermore, functional requirements should be stated regardless of time
or cost. The purpose of this part of the meeting is to extract every possible idea from every
stakeholder in the room. Many of the ideas will never get into the project, but we want to make
sure that every stakeholder’s idea is heard. One key to getting buy-in is that each person’s idea
must be captured and treated with respect by the group. The facilitator must take great care to
guide this part of the process. No one should be allowed to criticize an idea at this point, and
everyone should be encouraged to state all ideas no matter how wild they might seem.
After creating a list of functions, place them before the group on a dry-erase board or large
sheets of paper. Now, ask the group to prioritize the list. Prioritization is done by using a sim-
ple A-B-C scheme. The group will be asked to vote A, B, or C for each function listed. From
this vote, the facilitator will declare each function as A, B, or C based on the following
definitions:
Designing COM+ Applications
57
CHAPTER 3

Priority Definition
A Absolutely required
B Enhances the product
C Nice to have but not crucial
Obviously, various stakeholders will have different ideas about what requirements are
absolutely essential. However, the process demands that they convince others in the room that
the functionality is essential; otherwise, the group will cumulatively vote for a B or even a C.
This group ranking is critical for eliminating extraneous features and constraining the scope of
the project. We also see that stakeholders are willing to accept the judgment of their colleagues
in regard to the feature set. This process leads to buy-in because each stakeholder has a chance
to make his case whether he ultimately prevails. As an example, Table 3.1 shows the typical
output from a facilitated session with stakeholders. Notice that each function is stated simply
with limited detail.

TABLE 3.1 Prioritized Requirements


Function Ranking Description
Personalization and Membership A Users should be able to personalize,
3
create wish lists, and use shopping

APPLICATIONS

DESIGNING
carts.

COM+
Search and Navigation A Users should be able to search by
Improvements various keys and navigate the site based
on these keys.
Promotional Enhancements A Site should offer coupons and email
announcements.
Usage Analysis B We need to understand how promo-
tional activities result in sales.
Online Reviews C Users should be able to review books
online.

Assessing Requirements
After the prioritized list of requirements is complete, meet alone with the champion.
Ultimately, the champion has veto power over any decisions made by the group. A wise cham-
pion will be careful, however. Throwing out the stakeholders’ work will create dissention and a
feeling that the sessions were simply pandering and a waste of time. In the end, however, the
champion must be comfortable that the list of features can be presented to management and
successfully funded.
Understanding COM+ Applications
58
PART I

To aid in the assessment of the function list, create a new level of detailed description. To
arrive at the next level of detail, the champion is asked to identify domain experts for each fea-
ture on the prioritized list. A domain expert is someone highly knowledgeable in the require-
ments for the function. For example, the champion might identify a salesperson as the domain
expert for promotional features. Allowing the champion to identify domain experts helps elimi-
nate project enemies from the process. Everyone had a chance to be heard at the initial meet-
ing, but if isolating a person is required to ensure success, this is where it happens.
For each feature rated A or B, define several options for implementing the feature based on
interviews with the domain expert. In these interviews, we ask the domain expert to identify
the ultimate solution for the problem regardless of cost and time, a middle-of-the-road solution
that considers cost and time, and a “bare bones” solution that will work in a pinch. The idea is
to give the champion a large menu of options from which she can assemble a system that fits
into her priorities, time, and budget.
At the end of this process, we produce the first deliverable, or artifact. The artifact is a docu-
ment capturing all the functional requirements and showing a high-level view of the system. I
like to think of this artifact as a restaurant menu. The idea is to allow the champion to see all
the features and implementation options gathered throughout the meetings and interviews.
Provide rough cost estimates so that a system can be envisioned and presented to management
for approval and funding.
The process outlined here can take considerable time. For an average Windows DNA project,
this can be 40–80 hours. If you could have dedicated access to every stakeholder, you might
reasonably assume that you could accomplish the process in two weeks. However, stakeholders
are never completely dedicated to the process. Therefore, I find that it typically takes 4–8
weeks before the final artifact is reviewed, approved, and funded.
This can easily be the first crisis point for your project. I find that many customers still believe
that Windows applications can be created in a matter of weeks, on a shoestring budget, with
poorly defined and shifting requirements. In fact, I’ve lost jobs because the customer lost faith
in the process and believed it took too long. Perhaps you’ve had this experience and right now
you are thinking, “This is all great, but I’ll never be allowed to do it.” I understand completely.
The reality of software development remains: Nearly half of all software projects are canceled
before they are completed. Why? In my experience, software projects fail because the stake-
holders didn’t understand the need for design and lost faith in the process. So your choice is
simple: do you want your software project to fail, or do you want to take more time?

Describing the System


After the functional requirements are gathered, you are ready to create a text-based model of
the system. Designing a system is really a process of creating even more detailed models.
This enables the system to be evaluated and changed more easily than if you move directly
Designing COM+ Applications
59
CHAPTER 3

from requirements to code. The text-based model of the system is created through a set of
use cases. A use case is a description of the set of steps necessary to accomplish a function.
A complete set of use case describes at least 80% of the system and is the basis for more
detailed modeling.

Identifying Actors and Use Cases


Before you can create a use case, you must identify the actors involved in your system. Actors
are people or other systems that will interact with your system. The key to identifying an actor
is that the person or system must receive something of value from your system. For example, a
customer might receive a product from the system, or the company billing system might
receive the required information to create an invoice.
When defining actors, be careful to define them generically based on role and not based on job
title. This is because many people in an organization can fill a role. For example, if all the
sales personnel are at a meeting, the company vice president might pick up the phone to take
an order, thus becoming a salesperson. Typical actors include customer, salesperson, and
manager.
When the actors are identified, you can match them with the use cases they affect. When ini- 3
tially identifying use cases, limit them to simple one-line phrases. Later, you will expand the

APPLICATIONS

DESIGNING
detail in each use case, but for now you are trying to create a system outline based on the

COM+
actors and use cases.
Naming actors and use cases takes practice, but remember that an actor interacts with the sys-
tem to receive a value. The use case is a functional name of the value received. A simple exam-
ple is to name an actor as “customer” and the use case as “purchase product.” In this example,
the customer interacts with the system and the value received is a product.
As I stated earlier, system design is really a set of models used to describe the system. These
drawings and descriptions are the blueprints used to create the system. Imagine a set of blue-
prints for a house or electrical schematics for a computer. In both cases, you can imagine a set
of drawings that completely defines the product to build. Each set of drawings also has its own
set of symbols that are unique to the profession in which they are used. Software modeling is
no different. In our profession, we use the Unified Modeling Language (UML) to represent the
elements in the system.
UML is a series of symbols that help us create the various artifacts in the design process. UML
can be used for simple models such as use cases or more complex models that define the entire
system in great detail. I will use UML throughout the rest of the chapter to create various mod-
els.
Although You will ultimately create a complete text-base set of use cases, the first artifact you
create in the modeling process is the use case model. This model is a visual representation of
the actors and the use cases. Although this model is extremely simple, I have found that it
Understanding COM+ Applications
60
PART I

serves as an invaluable graphical overview of the system. To create the use case model, we use
the UML symbol for an actor and the UML symbol for a use case. Figure 3.1 shows these
symbols.

Actor Use Case

FIGURE 3.1
The UML symbols for an actor and a use case.

When modeling use case, we use an arrow to indicate how the actor interacts with the system.
If the actor initiates the use case, the arrow moves from the actor to the use case. If the use
case is initiated by the system itself, the arrow moves from the use case to the actor. Figure 3.2
shows a simple use case model for a customer interacting with a Web site.

Purchase
Product

Customer

Show Promotions

FIGURE 3.2
A simple use case model.

Documenting the Use Cases


Along with the use case model, you must create the text-based documentation mentioned ear-
lier. Documenting the use case provides the underlying detail necessary to fully understand
how the actor interacts with the system. Information required for the use case documentation is
typically gathered through one-on-one interviews with domain experts and other interested par-
ties. Just like the facilitated sessions I discussed earlier, the interview process requires experi-
ence and skill to complete successfully.
During the interview process, I typically ask the person to describe the sequence of events they
go through to complete a task. For example, you might ask the person to describe how they
take and process an order. The person will then explain what forms are filled out, what depart-
ments are notified, and other key pieces of information.
Designing COM+ Applications
61
CHAPTER 3

The goal for the application architect is to completely understand the process so that it can
faithfully be rendered in code. Sometimes, the architect might know key pieces of information
based on previous discussions or even his own experience. However, I often find that certain
surprises emerge during these interviews.
In my experience, all companies have discrepancies between the way they think they operate
and how they actually operate. When interviewing personnel for use case documentation, it’s
important to document how the business actually operates. In fact, it’s often a good idea to
have management personnel present during the interview process so that they can hear directly
from the employees how work is actually accomplished. This often leads to a reengineering of
the business processes within the company. Interviews lead to discovery; discovery leads to
improvement—it’s the improved processes that you want to build into your final software.
When you document use cases, use a Microsoft Word template and fill in the required informa-
tion. In the following sections, I will go over each part of the template. Figure 3.3 shows a
completed use case that describes how to log in to a Web site.

APPLICATIONS

DESIGNING
COM+
FIGURE 3.3
A typical use case document.

Header Section
This section has the key identifying information for the use case. Included in this section are
the name of the use case, the primary and secondary actors, the domain experts, the revision
number, and the revision date. All this information is easily retrieved from the information
already captured in the design process. For the use case shown in Figure 3.3, the following
information was captured:
Understanding COM+ Applications
62
PART I

• Use Case Name: Use Case—Log In


• Primary Actor: Customer
• Secondary Actor(s): Administrator
• Domain Expert(s): Scot Hillier
• Revision: 1.00
• Revised Date: 12/20/99

Use Case Purpose


This section defines the value received by the actor from the use case. Stating the purpose
forces you to justify the reason this use case was created. Identifying the correct number of use
cases requires experience. For example, would you create a separate use case for adding, edit-
ing, and deleting records in a database, or would you create just one? Answers to these ques-
tions depend on the system you are designing. If you can’t clearly state the value received by
the actor, you haven’t correctly defined the use case. For the use case shown in Figure 3.3, the
following purpose was stated:
• use case Purpose: The purpose of this use case is to describe how users log in to the
Web site.

Conditions and Rules


This section defines the preconditions, postconditions, and business rules associated with the
use case. Preconditions must be met before the use case begins. Postconditions are the output,
or value, provided to the actor. Business rules are the governing statements that determine how
the application will function.

Key Principle
Failure to properly identify business rules and conditions is the cause of nearly all cost
and schedule overruns.

Throughout the interview process, you must be on guard to properly identify conditions
and rules. These conditions and rules are the cause of nearly all middevelopment delays in
improperly designed software. How many times have you created a software solution only to
have the customer tell you that the business doesn’t work the way the software does? For the
use case shown in Figure 3.3, the following information was gathered:
• The Use Case Begins When: The customer navigates the browser to the Web site.
• Precondition(s): 1) A valid customer account and channel file exist. 2) A valid
customer-administration LDAP account exists.
Designing COM+ Applications
63
CHAPTER 3

• Postcondition(s): The customer is logged in.


• Business Rules: If the customer account has been inactive for 6 months, disable the
account.

Scenario List
This section describes the various scenarios that can occur to fulfill the use case. A scenario is
simply a set of steps that occur in the use case. In all use cases, you have three different types
of scenarios: Perfect, Alternate, and Exception.
• The Perfect scenario is what developers always consider when building an application—
even if they don’t have a design process. The Perfect scenario is the set of steps that
occur if there are no problems. This is generally the easiest and best-understood of all
the scenarios.
• Alternate scenarios represent variations on the Perfect scenario. These sets of steps
accomplish the same task, but not in the most straightforward way. In my example, for
instance, a user might log in through an HTML form, but if he has logged in before, you
can use a cookie to authenticate. The cookie authentication is an Alternate scenario.
• Exceptions are the set of steps executed when a problem occurs. Every use case must 3
deal gracefully with errors. What happens if the username and password are wrong?

APPLICATIONS
What if the credit card isn’t valid?

DESIGNING
COM+
In poorly designed systems, Alternate and Exception scenarios are always handled as the code
is written. Quite often, this leads to confusing and strange system behavior that leaves users
unsatisfied. For the use case shown in Figure 3.3, the following scenarios were defined:
• Scenario List: 1) Perfect: First Log In 2) Alternate: Cookie Authentication 3) Exception:
Improper username or password
Flow of Events
After all the scenarios are defined, document the series of steps for each of them. These steps
are contained in this section of the use case documentation. The flow of events is a narrative
flow chart that can be easily followed to understand the system behavior. For the use case
shown in Figure 3.3, the following steps were identified:
• Basic Path: First Log-In
The use case begins when the customer navigates to the site.
Because the customer has never been to the site before, she is presented with a home
page that welcomes her and asks her to log in.
The customer clicks the log-in link and is taken to an HTML form.
The form is filled out with a valid username and password.
Understanding COM+ Applications
64
PART I

If the username or password is incorrect, an error occurs (see improper user name or
password).
When authenticated, the system puts a cookie on the customer’s machine so future log in
is unnecessary.
• Alternate Path: Cookie Authentication
If a customer has logged in previously, the installed cookie is used to authenticate her.
• Exceptions
Any improper login results in an error message and a return to the start page.

Flow Charts
The flow of events created for the use case is useful in understanding how value is returned to
the actor; however, sometimes a visual representation can be useful as well. To this end, create
simple flow charts for each use case. For the use case shown in Figure 3.3, Figure 3.4 shows a
flow chart.

Does user have


[ No ] a cookie?
[ Yes ]

Enter User Name


and Password

[ No ]
Is cookie valid?

Are User Name and


Password Authentic? [ Yes ]
[ No ]
[ Yes ]

User Name
Cookies written to client.

Logged In

FIGURE 3.4
Use flow charts to help describe the flow of events.
Designing COM+ Applications
65
CHAPTER 3

Creating the Paper Prototype


After the use cases are complete, you will have a strong description of the system and how it
functions. You should have a good understanding of the system flow and the rules by which it
will interact with users. At this point, you are ready to create the paper prototype. The paper
prototype, also know as the storyboard, is a set of drawings that shows every screen in the sys-
tem. The objective is to bring the use cases to life and prove that your system will work
when built.
At first, you will be tempted to create the paper prototype by using Visual InterDev to mock up
screens and then show them to the user. Nothing could be worse. When you use a development
tool to create the paper prototype, two bad things happen:
• Users are reluctant to mark up anything that looks complete. Screen shots from your
computer have a professional finish that makes it look like they are difficult to change.
This will stifle user input.
• After you commit time to create the screens, you will be reluctant to throw them away.
As a result, you will be stuck with much of the work whether it’s good or not. I have
seen many so-called prototypes end up being the final product because no one wanted to 3
throw them away.

APPLICATIONS

DESIGNING
The correct way to create a paper prototype is with a drawing program like Visio, or better yet,

COM+
paper and pencil. You want the user to feel that the screens are easily changed and only repre-
sent a concept that can be modified. You’ll create a full set of screens as you envision the sys-
tem. Then take the screens and validate them against the use cases we created. In this process,
walk through every scenario in every use case and prove to yourself that they will work with
your system.
After you convince yourself, take the screens to your users. Place the screens in a stack in front
of the users and ask them to use the application. As they “click,” move the screens in the stack
showing them how the application works. Make notes directly on the screens where problems
arise.
Going through the paper prototype with the users produces profound benefits. Perhaps the
most important benefit is that it sets the expectations of the users. What they see in the paper
prototype is exactly what they will see in the final product. If users never see any screens until
the product is complete, they are bound to be dissatisfied. However, if they are involved
throughout the process, delivering the software is anticlimactic. This is exactly what you want.
Keep modifying the screens until the users are satisfied. You are then ready to define the soft-
ware that goes behind the screens.
Understanding COM+ Applications
66
PART I

System Modeling
To define how the software will be written to code the screens, we again return to modeling.
This time, however, you will be modeling the actual components that live behind the screens.
These models become the input used by the developers to create the system.

Database Model
The first model we create is the database model. Database models are perhaps the best under-
stood of all system models. In nearly all projects, even poorly designed ones, some kind of data-
base model will be created. Properly modeling a database is beyond the scope of this book, but
most developers are at least familiar with the process of identifying entities and relationships.
Entities in database design are similar to classes in object-oriented (OO) design. You can also
think of them as nouns. These are the items involved in the business problem. Typical entities
include customers, invoices, and products. Don’t confuse entities with actors, which must
derive value from the system. Entities are part of the informational structure of the system.
Each entity in the database has relationships with other entities. Database design typically uses
one-to-many and many-to-many relationships. Developers are generally familiar with these
concepts and, in my experience, this is a strength of the programming community. Therefore, I
won’t spend time discussing them in detail. Figure 3.5 shows a typical database model.

FIGURE 3.5
Database models show entities and relationships.
Designing COM+ Applications
67
CHAPTER 3

Logical Model
Although most developers can create a database model, few have actually created a logical
model. A logical model represents the software classes in the system. Just as a database model
can be used to create a database, the logical model can be used to create COM+ components.
Almost anyone can learn to successfully create use cases, but jumping from use cases to a logi-
cal model takes a tremendous amount of experience. Often, companies will employ “business
analysts” to produce use cases, but the logical model can be created only by a true software
architect.
The goal of a logical model is to create a completely defined model that contains the name and
definition of every class in the application with 80% accuracy. That’s right—the software
architect must define every class, every method, and every property without ever writing a sin-
gle line of code. This is why the software architect must be an experienced developer who
understands the use cases completely.
So how does someone begin to define every class, method, and property for a large, complex
system? The answer is to use a framework. If you approach the design of every system as a
unique endeavor, you are destined to fail. Instead, you must have a repeatable methodology for 3
achieving success. To use current trendy terminology, you need a pattern.

APPLICATIONS

DESIGNING
A pattern is a predefined solution to a problem. Although every software development project

COM+
has some unique features, most Windows DNA applications have more in common than not.
For this reason, you can create a development pattern that leads to success. Essentially, this
book is dedicated to developing that pattern. Therefore, you will better understand how to
make the leap from use cases to logical model by the time you reach the project in Chapter 16.
For now, stick to the simple process defined in the previous use case—that is, define a system
that allows you to log in to a Web site.
As you will see later in this book, we normally build the logical model from the data sources
to the Web pages. Beginning with this idea, one of the first things you might do is to define a
data class that accesses the Windows 2000 Active Directory to return identifying information
for the user. You could say, for example, that you’d like to welcome the user to your site by
using their nickname or “friendly name.” Your login could consist of looking for this informa-
tion. If you find a friendly name, the login is authentic; otherwise it’s not.
To define your new data class, again use UML. UML provides symbols for defining classes as
well as components such as ActiveX DLLs. The UML-compliant Microsoft Visual Modeler
can be used to create logical models. If you created a new class named CData, it would appear
in the Visual Modeler as shown in Figure 3.6.
Understanding COM+ Applications
68
PART I

<<Class Module>>
CData

FIGURE 3.6
The UML symbol for a class.

Along with the class itself, we will define a method to return the friendly name of the user.
Even without writing code, we have enough information to define the method. First, we can
decide on a name for our method; we’ll call it GetFriendlyName. Next, we know that the
inputs to the function must be the username and password. Finally, the output will be the
friendly name as a String. Therefore we could define the method and show it in the UML
model of Figure 3.7.

<<Class Module>>
CData

Public Function_
GetFriendlyName

FIGURE 3.7
Defining methods in UML.

UML classes can show as much information about the class as you want. In addition to func-
tion names, you can show input and output parameters, interfaces, and data types. The idea is
to provide enough information so that a competent programmer can create the class. All that
needs to be done is to fill in the code within the method definitions for each class and the soft-
ware will be complete.
When I present this concept of designing down to the method level, different people have vari-
ous reactions. Some developers enthusiastically declare that they would love to receive this
kind of detail from an architect. Others are suspicious, almost afraid that their job is being
taken away. To me, the point is to create great software. I know from experience that the peo-
ple writing the code are the least likely to perform rigorous design. Instead, the plan needs to
be given to the team at the outset. This is the equivalent of a building architect giving blue-
prints to the general contractor. No one wants the carpenters deciding where the bathrooms go
as they build the house.
In the end, the logical model forms the foundation of the OO design. Each class must be prop-
erly designed, documented, and delivered to the development team. Keep in mind that the goal
of design is 80% accuracy. Problems certainly will arise during the development process;
Designing COM+ Applications
69
CHAPTER 3

however, my experience is that design is no longer cost-effective when you try to reach beyond
the 80% mark.

Three-Tier Diagram
One of the most useful ways to present the classes you’ve designed is through a three-tier dia-
gram. The three-tier diagram shows all the classes you’ve designed broken into their associated
tier. In this way, developers can see what classes make up data services, business services, and
user services. The three-tier diagram doesn’t require any new work on your part; it’s simply a
convenient way of showing the required classes. Figure 3.8 shows a typical three-tier diagram.

<<Active Server Page>> <<Class Module>> <<Class Module>> <<Class Module>>


order.asp CCreateCart CGetCartDetails CUpdateCart
(from ASP) (from Cart) (from Cart) (from Cart)

<<Class Module>>
CCart
<<Active Server Page>> (from Cart)
contents.asp <<Class Module>> <<Class Module>> <<Class Module>>
(from ASP) CPutOrder CPutCartItem CDeleteCartItem
(from Cart) (from Cart) (from Cart)

<<Active Server Page>> <<Class Module>>


3
home.asp CPutADSIAAddress

APPLICATIONS
(from ASP) (from Membership)

DESIGNING
COM+
<<Class Module>> <<Class Module>>
CMembership CPutADSIAddress
(from Membership) (from Membership)
<<Active Server Page>>
validate.asp
(from ASP)
<<Class Module>>
CGetADSIFriendlyName
(from Membership)
<<Active Server Page>>
shipping.asp
(from ASP)

<<Class Module>>
CGetBookDetails
<<Active Server Page>> (from Books)
<<Class Module>>
results.asp CGetTitlesByPublisher
(from ASP) (from books)
<<Class Module>>
CBooks
<<Class Module>>
(from Books)
<<Active Server Page>> CGetTitlesByAuthor
details.asp <<Class Module>> (from books)
(from ASP) CGetTitlesByTitle
(from Books)

FIGURE 3.8
Three-tier diagrams help developers understand a system.
Understanding COM+ Applications
70
PART I

EXERCISE 3.1

Using Visual Modeler


The Microsoft Visual Modeler can be used to help design and build COM+ applications. In this
exercise, you will use Visual Basic and the Microsoft Visual Modeler to create an application
that retrieves information about resources available on a network machine.
Building the New Model
Step 1
In the Windows Explorer, create a new directory named COM+/MODELER.

Step 2
Start a new Standard EXE project in Visual Basic. Because this project uses the Visual
Modeler, you must set up Visual Basic to use round-trip engineering by enabling the Visual
Modeler add-ins. Open the Add-In Manager by selecting Add-In Manager from the Add-Ins
menu. In the Add-In Manager (see Figure 3.9), activate Visual Modeler Add-In and Visual
Modeler Menus Add-In. Visual Modeler expects these add-ins to be present whenever Visual
Basic is running. Therefore, check the Load on Startup option for each add-in. Click OK to
close the Add-In Manager.

FIGURE 3.9
Enable the Visual Modeler add-ins to load on startup.

Step 3
Open the project properties dialog by selecting Project1 Properties from the Project menu. In
the project properties dialog, change the name of the project to FrontEnd. Close the dialog.
Designing COM+ Applications
71
CHAPTER 3

Step 4
Select Form1 in Project Explorer. In the properties window, change the name of Form1 to
frmClient.

Step 5
Add a new ActiveX DLL project to Visual Basic by selecting Add Project from the File menu.
This component will be the business object you will use to retrieve information about a host
computer. Open the project properties dialog for the ActiveX DLL project. Change the name of
the project to MemoryUsage. While the dialog is open, make sure that the threading model is set
to apartment threading.

Step 6
Select Class1 in the Project Explorer. Change the name of the class to DataClass.

Step 7
Save your project into the directory you created earlier.

Step 8
Visual Modeler works with Visual Basic to build models from code and code from models. 3
This process, round-trip engineering, is used to create a new model from this project. Select
the FrontEnd project in the Project Explorer. Create a new model for this project by selecting

APPLICATIONS

DESIGNING
COM+
Visual Modeler and then Reverse Engineering Wizard from the Add-Ins menu.

Step 9
The Visual Modeler add-in presents you with the model selection dialog (see Figure 3.10).
Click the New button to build a new model. This will start Visual Modeler.

FIGURE 3.10
Select to create a new model.
Understanding COM+ Applications
72
PART I

NOTE
Sometimes when you reverse engineer a form, Visual Modeler will give an error stat-
ing that no project was selected. If this happens, save your work and then reverse
engineer the project directly from Visual Modeler by choosing Visual Basic and then
Reverse Engineering Wizard from the Tools menu.

Step 10
The first step of the Reverse Engineering Wizard is an introduction screen. Click Next to move
to the next step.

Step 11
The second step of the wizard (see Figure 3.11) asks you to select which components to
reverse engineer. The wizard works with only one project at a time, so it displays only the form
from the FrontEnd project, not the class from the ActiveX DLL. Accept the default settings
here and click Next.

FIGURE 3.11
Accept the default settings to reverse engineer the FrontEnd project.

Step 12
The third step of the wizard (see Figure 3.12) asks you to assign the form to one of the three
tiers in the model. Carefully drag frmClient to the User Services folder and drop it. The
Visual Modeler displays the form as a member of the user services layer. Click Next.
Designing COM+ Applications
73
CHAPTER 3

FIGURE 3.12
Assign the form to the User Services layer.

Step 13
The wizard now displays a summary of the conversion work. Read the summary and then click 3
Finish to build the model. When the wizard is finished, you will see a component labeled

APPLICATIONS
frmClient in the user services layer.

DESIGNING
COM+
Step 14
Immediately save the model to the directory you created earlier. Name the file modeler.mdl.

Step 15
Minimize Visual Modeler and return to Visual Basic. Now select the MemoryUsage project
from the Project Explorer. Reverse engineer this project by selecting Visual Modeler and then
Reverse Engineering Wizard from the Add-Ins menu. When the model selection dialog
opens (see Figure 3.13), select to reverse engineer into the same model you built for the
FrontEnd project.

FIGURE 3.13
Select to add to the existing model.
Understanding COM+ Applications
74
PART I

Step 16
This time, work your way through the wizard, but make the DataClass object part of the busi-
ness services layer. When you have both the form and the class in the model, save the model.

Step 17
With Visual Modeler, you can create properties, methods, and associations for objects in the
model. First, we’ll create an association between the form and the class. On the Visual Modeler
toolbar, carefully locate the Unidirectional Association button (shown in the margin next to
this paragraph). This button allows you to specify that the form will contain an instance of the
class.

Step 18
Click the Unidirectional Association button and drag an association from the form to the
class. When the line appears showing the association, double-click it to open the Association
Specification dialog.

Step 19
The Association Specification dialog allows you to establish how code is generated from the
relationship. On the General tab (see Figure 3.14), you can name the roles that each compo-
nent fulfills. In the dialog, role A is the class and role B is the form. Name the role for A as
objData. Name the role for B as objFrontEnd.

FIGURE 3.14
Name the roles for the object and form.

Step 20
Click the Visual Basic A tab. This tab designates how property procedures should be created
for the component in role A (see Figure 3.15). When you first create the relationship,
Designing COM+ Applications
75
CHAPTER 3

properties aren’t automatically created. However, you can change these characteristics. Click
the Edit Set button to edit the property procedure characteristics. This opens the Options
dialog.

FIGURE 3.15
Use the Edit Set button to affect code generation for the relationship.
3

APPLICATIONS

DESIGNING
Step 21

COM+
In the Options dialog (see Figure 3.16), you can create new sets of property procedure attrib-
utes. Click the Clone button to define a new set of property procedure characteristics. You will
be prompted to name the new set. When prompted, name the new set Child. Click OK.

FIGURE 3.16
Use the Clone button to create a new set of relationship attributes.
Understanding COM+ Applications
76
PART I

Step 22
The Child set now is a clone of the default set. In the characteristics list, change the following
characteristics:
New True
Generate Get Operator True
Generate Set Operator True
Figure 3.17 shows the completed set of new attributes.

FIGURE 3.17
Change the relationship attributes after cloning.

Step 23
Changing the characteristics for code generation will create an instance of the class module
and generate a set of property procedures. After you change the characteristics for the Child
set, click OK to exit the editing dialog.

Step 24
Now that you’ve created a new set of characteristics, choose the Child set for the object in role
A. Click OK again to exit the specification dialog.

Step 25
Right-click the DataClass object in Visual Modeler and select Open Specification. This opens
the specification dialog in which you can add new properties and methods (see Figure 3.18).
Click the Methods tab.
Designing COM+ Applications
77
CHAPTER 3

FIGURE 3.18
The specification dialog allows you to create new methods for a component.

Step 26
In the list view window of the Methods tab of the specification dialog, right-click and select
Insert. This adds a new method template called NewMethod. Change the name of this method 3
to Process by typing directly into the list in which the new method appears. Set the return type

APPLICATIONS

DESIGNING
of the method to Long by using the drop-down list. Click OK to close the specification dialog.

COM+
Figure 3.19 shows the completed method definition.

FIGURE 3.19
Close the specification dialog when the method is defined.

Step 27
Save the model.
Understanding COM+ Applications
78
PART I

Coding the Application


Step 28
Now that you’ve added an association and a method, you are ready to generate code. Select to
generate code for both the form and the class by choosing Select All from the Edit menu.
Then start the Code Generation Wizard by choosing Generate Code from the Tools menu.

Step 29
The first step of the wizard is just an introduction screen. Click Next to continue.

Step 30
In the second step of the wizard (see Figure 3.20), you are asked to select the classes you want
to generate code for. Notice in this dialog that you can’t generate code directly for forms.
Visual Modeler generates only new classes. To use Visual Modeler with a form, the form must
already exist in a project. Click Next.

FIGURE 3.20
Select the classes to generate code.

Step 31
In the wizard’s third step, you can preview the code it generates. This lets you modify the defi-
nitions of properties and methods before generating the code. Click Next.

Step 32
The wizard’s fourth step allows you to specify general coding options such as error handling
and debugging code (see Figure 3.21). Clear all these check boxes except Save Model and
Project Before Generating Code. Click Next.
Designing COM+ Applications
79
CHAPTER 3

FIGURE 3.21
Clear the special coding options before generating code.

Step 33
The fifth step is a summary of work to be done by the wizard. Review this screen and then 3
click Finish to generate your code.

APPLICATIONS

DESIGNING
Step 34

COM+
When the wizard is finished, close it and save your model.

Step 35
Close Visual Modeler and return to Visual Basic. When you return to VB, you will see that
Visual Modeler has added the Process method as well as some comments that contain infor-
mation about the model. Also notice that the Project Explorer now contains an entry for the
model in the Related Documents folder.

Step 36
Although Visual Modeler generates the members for a class, it doesn’t implement the class.
You must still write the code yourself. In this exercise, use the GlobalMemoryStatus API call
to return information about resource usage on a target machine. In the
[General][Declarations] section of DataClass, add the following code to declare the API
call and associated structure. You might want to use the Visual Basic API Viewer to retrieve the
definition for the API call and structure.
Private Declare Sub GlobalMemoryStatus Lib “kernel32” _
(lpBuffer As MEMORYSTATUS)

‘Structure for data


Private Type MEMORYSTATUS
Understanding COM+ Applications
80
PART I

dwLength As Long
dwMemoryLoad As Long
dwTotalPhys As Long
dwAvailPhys As Long
dwTotalPageFile As Long
dwAvailPageFile As Long
dwTotalVirtual As Long
dwAvailVirtual As Long
End Type

Step 37
The Process method makes the API call and returns information about memory usage. The
GlobalMemoryStatus API can return a lot of different information, but in this exercise, you
will return an indicator of the percentage of memory in use. Add the following code to the
Process method to retrieve the information and pass it to the calling client:

On Error GoTo ProcessErr

‘Variables
Dim objMemory As MEMORYSTATUS

‘Get System Data


objMemory.dwLength = Len(objMemory)
GlobalMemoryStatus objMemory
Process = objMemory.dwMemoryLoad

Exit Function

ProcessErr:
App.StartLogging “”, vbLogAuto
App.LogEvent Err.Description, vbLogEventTypeError

Creating the Front End


Step 38
The front end for this application uses a form to display the available resources for any
machine that has the MemoryUsage component installed. Open frmClient in Visual Basic.
Figure 3.22 shows how the form is constructed.
Designing COM+ Applications
81
CHAPTER 3

FIGURE 3.22
This is the front end for the exercise.

The form uses a single TextBox and a ProgessBar control. If a ProgressBar control isn’t in
your toolbox, you must insert it by selecting Microsoft Windows Common Controls 6.0 in the
components dialog. Set the design-time properties as follows for the controls on the form:

Control Property Setting


Form Caption Memory Usage
Label Name lblMachine
Caption Machine Name 3
TextBox Name txtMachine

APPLICATIONS
Text Leave empty

DESIGNING
COM+
CommandButton Name cmdGO
Caption GO!
Label Name lblLoad
Caption Memory Load
ProgressBar Name pbrLoad

Step 39
You want this form to be able to call the MemoryUsage component on any machine, so we will
use late binding to create it. Therefore, add the following code to the
[General][Declarations] section:

Private objBusiness As Object

Step 40
All the action takes place when the button is clicked. In this event, create an instance based on
the name typed into the TextBox and call the object to get a percentage of the memory in use
on that machine. The value is then presented in the progress bar. Add the following code to
cmdGO_Click to call the business object:

Set objBusiness = CreateObject(“MemoryUsage.DataClass”, txtMachine.Text)


pbrLoad.Value = objBusiness.Process
Understanding COM+ Applications
82
PART I

Step 41
Try running the front end and calling your local computer to see the percentage of memory in
use. When you first run this application, you will likely notice that it often returns a value of
zero. This is true if you have very little activity on your system. The memory load will change,
however, if you analyze the system while performing an intense operation such as a query.
COM+ Application CHAPTER

4
Fundamentals

IN THIS CHAPTER
• Understanding Contexts 84

• Object Activation 88

• Managing Shared Properties 102


Understanding COM+ Applications
84
PART I

The history of business application development on the Windows platform has been one of
increasingly complex frameworks and abstractions designed to decrease development times
while enhancing performance. I often like to talk about the days before Visual Basic and the
effort required to create a Windows application. In the Windows world before 1991, creating a
Windows application meant coding a tremendous amount of tedious infrastructure by hand. For
example, you had to create all the code necessary to generate and display a window—for each
form in the application.
The attraction of a tool such as Visual Basic is that the infrastructure code is completed for
you. Forms can be treated as entities that already exist—you don’t have to explicitly create
them. The beauty of this framework is that developers are free to focus on the business prob-
lem and not the operating system.
This philosophy reached a significant level of maturity with the release of the Microsoft
Transaction Server (MTS). What Visual Basic did for form creation, MTS did for operating
system services. Before MTS, if you wanted to create an application that would scale to thou-
sands of users, you had to create your own infrastructure code to manage threads, memory, and
database connections. With the release of MTS, developers were again freed to concentrate on
the business problem and simply use the services provided by MTS.
COM+ is the next evolutionary step for business application developers. COM+ provides the
same abstracted access to operating system services introduced by MTS, but completely inte-
grates these features with the operating system itself. MTS was a separate product; COM+ is
an integral part of the operating system. In this chapter, we will examine the fundamental
concepts and services that constitute COM+ and provide a strong foundation for the develop-
ment of a distributed system architecture.

Understanding Contexts
COM+ has many features and can be described from many different perspectives, but the sim-
plest way to think of COM+ is as a safe and comfortable environment for your objects. Within
this safe environment, COM+ provides security, support, and meaning to your objects. To
achieve support and security, COM+ is integrated with the operating system to provide a set of
concentric containers, each with its own responsibility. There are three levels of concentric
containers: processes, apartments, and contexts.
A process is essentially an executable running inside the operating system. A process is started,
for example, any time you run a Visual Basic standard EXE. COM+, however, has its own
process that runs for each COM+ application you define. This process is dllhost.exe.
Component Services starts a copy of dllhost.exe for the purpose of loading your Visual Basic
DLLs when they are invoked, and there is a one-to-one mapping between COM+ applications
that you define and running instances of dllhost.exe. You can actually see how many COM+
applications are running by examining the task manager shown in Figure 4.1.
COM+ Application Fundamentals
85
CHAPTER 4

FIGURE 4.1
Each COM+ application you call creates an instance of dllhost.exe.

Processes are responsible for overall resource management, such as managing the thread pool
utilized by objects. dllhost.exe provides this type of resource management for COM+
components.
Inside each process are apartments. Apartments are responsible for implementing the threading
model for each component. Even though the process manages the thread pool, the apartments
manage whether a thread from the pool is allowed access to a component. Controlling the 4
access to a component is critical for synchronization, the management of thread access to an

FUNDAMENTALS
APPLICATION
object’s methods for the purpose of preventing collisions between the threads (see Figure 4.2).

COM+
If threads were allowed unrestricted access, one thread could easily corrupt the values of vari-
able data being used by another. As discussed previously, COM+ supports single-threaded
apartments (STA), multi-threaded apartments (MTA), and thread-neutral apartments (TNA).
All Visual Basic components are created as STA components.
Inside an apartment are contexts, which contain security and transactional information about
components. Contexts are new to COM+ but represent a natural evolution from the context
wrappers previously employed by MTS. Both contexts and context wrappers contain the same
types of information, but context wrappers are an artificial mechanism inserted by MTS to
manage components. In COM+, contexts are an integral part of the operating system and exist
whether or not you explicitly place your component in a COM+ application. Figure 4.3 shows
the relationship between processes, apartments, and contexts.
Understanding COM+ Applications
86
PART I

Apartment

Object
Instance

Thread Apartment
Pool coordinates
thread access to
the object

FIGURE 4.2
Apartments manage threads to ensure synchronization.

Process: DLLHOST.EXE

Single.Threaded Apartment

Context
Object

Context contains secutity and


transaction information
Apartment manages
synchronization

Process manages
thread pool

FIGURE 4.3
Process, apartments, and contexts work together in COM+.

Inside a context is an object. Because contexts always exist in COM+, created objects can be
placed either inside the existing context of the creator or in a brand new context. COM+
decides whether to create a new context based on whether the component is configured or
non-configured.
Configured and non-configured are new terms for COM+, but they have simple definitions.
Configured components are explicitly placed in COM+ applications using the Component
Services explorer. Non-configured components aren’t associated with a COM+ application.
Configured components are generally created in a new context, whereas non-configured com-
ponents are generally created in the context of the calling client. Figure 4.4 shows how config-
ured and non-configured components are placed in a context.
COM+ Application Fundamentals
87
CHAPTER 4

Non-configured
components are created
in the same context as
the creator

Object Creator non-configured


component

Object Creator's Context


Configured components are
created in a new context within
DLLHOST.EXE

Object Creator Proxy Stub configured


component

Object Creator's Context New Context created by COM+

FIGURE 4.4
Configured and non-configured components both reside in contexts.

In addition to having their own context, configured components in COM+ have their profiling
information stored in the COM+ system catalog when they are added to a COM+ application.
This information can then be accessed through the property sheet for the component or through
a programmatic object model. It’s this profile that makes COM+ programming so convenient.
You can easily change several attributes, such as transactional behavior, without re-coding the 4
component.

FUNDAMENTALS
APPLICATION
One supposed advantage of having the object’s context as an integral part of the operating sys-

COM+
tem is that you gain many of the benefits of the context without any additional code. If you
want to change the transactional behavior, just change the property value in Component
Services. If you want to change the way the object is activated, just change another property.
Under MTS, if you wanted to take advantage of the context wrapper, you had to explicitly
address the context wrapper from within your DLL code. This was done by getting a reference
to the ObjectContext from the MTS object library. After setting a reference to the MTS
library, the following code would produce an object reference to the context wrapper:
Set MyContext = GetObjectContext()
Understanding COM+ Applications
88
PART I

Once you had a reference to the context wrapper, you were expected to notify the context
about certain activities within your component. These notifications helped the context wrapper
manage resources for your component. The resource management features still exist in COM+,
but in theory you no longer have to code directly to the context. As we continue to investigate
the features of COM+, we will return to the idea of communicating with the context.

Object Activation
Memory and thread management are at the heart of COM+ services because they have the
greatest impact on application scalability. Now with the full integration of the context and
operating system, taking advantage of these resource management features can be as simple a
placing a DLL under the control of component services. Once a COM+ application is defined,
COM+ will automatically take care of creating an object instance within a context (known as
activating the object) and even destroy the object when a client is finished with it (known as
deactivating the object). Activating and deactivating object instances is the fundamental service
on which all distributed applications are based.
To understand the importance of activation and deactivation, consider the scenario in which a
component is installed in a COM+ application and a client wants to access the component. To
create an instance of the component, the client will, of course, have to declare a variable. For
the sake of argument, assume that the variable is declared in the [General][Declarations]
section of a standard module in the client. The application is written to create an instance of
the desired component in Sub Main as soon as the program starts. By design, the instance is
then maintained by the client until the application terminates. Now imagine that a user starts
the application, uses it for a while, and then goes to lunch. Because the instance variable is
maintained with application-level scope, the component in COM+ won’t shut down. This
means that valuable memory is used by the business services layer to maintain an instance that
isn’t in active use. Now imagine that hundreds of users log in to the application and also go to
lunch. Complete disaster.
Allowing clients to create and maintain instances in the shared business services layer will
destroy scaleability because the resources in the middle tier are limited. Instead, an application
should create an instance, make a method call, and then destroy the instance. Objects in the
middle tier must live for the minimum amount of time necessary to perform a function.
Your response to this situation might be to declare the variable with less scope. Perhaps we can
declare a locally scoped variable only in the procedures in which the application needs access
to the distributed component. This is certainly a better idea, but not the best. Local variables
will cause the component in COM+ to be created and destroyed many times, which doesn’t
give COM+ a chance to effectively manage memory. The essential problem in the design of the
application is that the client is controlling the management of resources in the middle tier
COM+ Application Fundamentals
89
CHAPTER 4

through variable scope. The best solution to instance management is to allow COM+ to auto-
matically manage the instances.
Directing COM+ to handle the activation and deactivation of your objects requires enabling
two settings for each component in the application. One setting establishes COM+ control over
activation, the other over deactivation. The activation setting appears in the component’s prop-
erty page as Enable Just In Time Activation (see Figure 4.5).

FIGURE 4.5
Activation is enabled from the component’s property sheet.

The phrase just-in-time (JIT) activation found on the property sheet refers to COM+ activating
an object instance only immediately before processing any client calls. This means that the
resources used by the object are claimed only for the minimum amount of time necessary to 4
process the method call. The beauty of this scheme, however, is that the client is unaware that

FUNDAMENTALS
APPLICATION
an object instance is created or destroyed. Only COM+ needs to know whether the object has

COM+
been activated.
Deactivating the object requires you to enable a different setting for your component.
Deactivation generally occurs at the end of a method call. Thus, COM+ activates an object
when a client makes a method call and deactivates the object when the method is complete.
You can set up deactivation for a method by examining the property sheet for any method and
enabling the setting marked Automatically Deactivate This Object When This Method Returns,
as shown in Figure 4.6. This setting is often referred to as the Auto Done property.
Understanding COM+ Applications
90
PART I

FIGURE 4.6
Deactivation is enabled from the method’s property sheet.

Although setting the Auto Done property ensures that the middle tier’s memory resources are
properly managed, you might be wondering what happens to the client application if it’s still
holding an object variable reference to the now defunct object. What happens when the client
uses the same instance variable to call the business object again? The answer is simple. COM+
creates a new instance of the desired object, and it is provided to the calling client. Although
the new instance is completely different from the original instance, the client is unaware of any
differences and happily accepts services from the new instance.

Key Principle
When creating clients that work with COM+ components, declare variables at higher
levels of scope rather than constantly creating instances and then setting them to
Nothing in the client code. Let the context manage the life of the business object for
you. This principle goes by the phrase “Create instances early, release them late.”

All of this is made possible through the work of the COM+ context. This is because when a
client holds a reference to an object running under COM+, it actually communicates with the
context and not directly with the business object. The context can provide the appearance of a
persistent business object to the calling client while COM+ recycles the objects behind the
scenes. This is done to ensure that clients can’t create instances in the middle tier and then sim-
ply hold them forever.
The concept of JIT is well thought out and generally would free you from having to write any
special code within your COM+ components, if it only worked as designed. Unfortunately, I
COM+ Application Fundamentals
91
CHAPTER 4

have discovered that deactivation doesn’t always occur correctly—particularly if your compo-
nent generates as an unhandled error. According to the COM+ documentation, unhandled
errors are supposed to result in deactivation of the object, but this doesn’t happen.

QUICK CHECK 4.1

Investigating Activation
1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 04\Quick Check 4-1. This directory contains a project you can use
to investigate the Auto Done property.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 4.1. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Open the compluserrors.vbp project in Visual Basic. This DLL contains methods that
complete successfully as well as generate errors.
4. Compile the DLL project and close Visual Basic.
5. Create a new COM+ application in the Component Services explorer named Just in
Time. Install the compiled component into the new COM+ application.
6. Open the property sheet for the component and examine the Activation tab. Notice that
the component is already set to enable JIT activation (see Figure 4.7).

FUNDAMENTALS
APPLICATION
COM+

FIGURE 4.7
Activation is already enabled.
Understanding COM+ Applications
92
PART I

7. Expand the tree view until you locate the four methods of the component. Open the
property sheet for the method HandledNoContext by right-clicking and selecting
Properties. On the General tab, enable the Auto Done property. Repeat this for the
UnhandledNoContext method. Don’t make changes to the other two methods. Figure 4.8
shows the tree view expanded to reveal the method names.

FIGURE 4.8
Access the properties of the methods.

8. Open the front end for the project in Visual Basic. This project is contained in the
frontend.vbp file. In this project, you need to set a reference to the compiled DLL.

9. After you set the reference, run the front-end project, but do not push the buttons yet.
Instead, use the Component Services explorer to display the status view for the
Components folder, as shown in Figure 4.9.

FIGURE 4.9
Display the component properties.
COM+ Application Fundamentals
93
CHAPTER 4

Notice that even though your front end has done nothing, a single instance has been acti-
vated. This is somewhat unexpected because JIT activation implies that the object is cre-
ated just before you need it.
10. Click the button on the front end form labeled Handled Error Using Auto Done Feature.
This method simulates a normal method call to the component with no unhandled errors.
11. Running the method causes the object to deactivate. That’s good! Now the object is no
longer consuming resources. Click the button again. The method will run indicating that
a new object was activated, and then COM+ will deactivate the object again. This is the
preferred behavior.
12. Now click the button labeled Unhandled Error Using Auto Done Feature. This button
simulates an unhandled error occurring within the method call. Notice that the object
instance remains activated, completely defeating the Auto Done feature.
This demonstration shows the danger of generating unhandled errors within COM+ compo-
nents. You should keep this project available because I will reference it later in my discussion.

Communicating with the Context


Although the property settings in the Component Services explorer provide a convenient way
to control activation, as we have seen the results can sometimes be incorrect. For this reason,
we might want to control the activation and deactivation more directly. This can be done by
communicating directly with the object context from our component code. We accomplish this
in COM+ in much the same way as with MTS, shown earlier.
To communicate with the context, we must first set a reference to the COM+ Services Type
Library. As with all object model references in Visual Basic, we set it with the References dia-
log. The reference should be set from within the ActiveX DLL project that will become your
4
business object. Figure 4.10 shows the references dialog box in Visual Basic.

FUNDAMENTALS
APPLICATION
COM+

FIGURE 4.10
Set a reference to the COM+ Services Type Library.
Understanding COM+ Applications
94
PART I

Retrieving a reference to the context is done with the COM+ API call GetObjectContext().
This function returns a reference that’s similar to any object reference held and managed in
Visual Basic. Therefore, you should simply declare a variable as the appropriate type and fill it
with the context reference. The following code shows how to retrieve the context for any busi-
ness object:
Dim objContext As COMSVCSLib.ObjectContext
Set objContext = GetObjectContext()

Retrieving the context is always done inside the component associated with COM+. No other
part of the application has any use for the context. A component with a reference to its context
should never attempt to pass that reference to another object because one component can’t use
the context for another component. The context returned by GetObjectContext() applies only
to the business object that called the function. Also, components should destroy the object vari-
able carrying the context after they finish using it. This destruction might be an explicit release
achieved by setting the variable to the VB keyword Nothing or an implicit release occurring as
the result of a variable losing scope.
Generally, a COM+ component retrieves a reference to its context and releases that reference
all within a single method call. Therefore, each method of the business object repeats the same
simple code at the beginning and end of the function. The following code shows a typical tem-
plate for a component method:
Public Function MyFunction() As Boolean

On Error GoTo MyFunctionErr

‘Get Object Context


Dim objContext As COMSVCSLib.ObjectContext
Set objContext = GetObjectContext()

‘Place Code Body Here!

‘Tell COM+ we are done


objContext.SetComplete

MyFunctionExit:
Exit Function

MyFunctionErr:
‘Tell COM+ we failed
objContext.SetAbort

Debug.Print Err.Description
App.StartLogging App.Path & “\error.log”, vbLogToFile
COM+ Application Fundamentals
95
CHAPTER 4

App.LogEvent Err.Description, vbLogEventTypeError


Resume MyFunctionExit

End Function

NOTE
Because the context code is redundant and must exist in every method, I have
included a special add-in on the CD-ROM that you can use to replace the standard
Visual Basic procedure dialog box with one that includes the ability to add COM+
code to a function. I find this utility useful in creating all kinds of standard method
structures, including error handling and property procedures. Although no exercise in
this book assumes that you have the enhanced procedure dialog, you might want to
install it to save work. Figure 4.11 shows the Enhanced Procedure dialog.

FIGURE 4.11 4
This dialog box writes template COM+ code for you.

FUNDAMENTALS
APPLICATION
COM+
The primary reason for referencing the context is to manually control activation or—as you’ll
see later—to vote in a transaction. By using the context, a business object can notify COM+
that the current object instance is ready for deactivation. Manually controlling activation and
deactivation is accomplished through the SetComplete and SetAbort context methods.
The SetComplete method of the context explicitly notifies COM+ that the state of the business
object is such that it can be freely deactivated. COM+ can then reuse the resources dedicated to
the current instance. If the object causes an error, the SetAbort method tells COM+ that the
business object can be deactivated, but that all work performed by the business object has
failed. Both SetComplete and SetAbort allow COM+ to reuse the currently occupied
resources, but SetAbort is specifically used by COM+ to roll back any transactions that this
object supported. Transactions are covered in detail in Chapter 7, “COM+ Transactions,” but
for now recognize that both of these methods simply enable activation and deactivation.
Understanding COM+ Applications
96
PART I

At this point, we should pause to summarize the options available for activation control. As a
COM+ developer, you can choose either to rely on the automatic activation and deactivation
supported by COM+ property settings, or control the process manually with SetComplete and
SetAbort. Officially, SetComplete and SetAbort exist only for backward compatibility with
MTS components. However, we are going to find that the issue becomes more complicated
when your components are involved in transactions. Furthermore, regardless of your imple-
mentation, unhandled errors will always prevent deactivation. At this point, you might want to
return to Quick Check 4.1 and try out the method calls that use SetComplete to see how they
behave.

CAUTION
Unhandled errors in COM+ components prevent proper deactivation.

State Management
Whether you choose to manage activation manually or through the use of the Auto Done fea-
ture, it stands to reason that the client can’t rely on the values of any variables within the com-
ponent to be persistent across calls. The actual instance provided by COM+ to a client will be
different each time the client calls a method. This is why developers are always discussing
stateless objects in COM+. Without object instance persistence, storing state in the object is
futile.

Key Principle
Because COM+ objects must constantly be recycled, they shouldn’t store applications’
state.

Because state can’t be kept in the business objects, we must move the stateful information out
of the business object and into another tier. This is accomplished by moving the stateful data
into either the database or onto the client machine. Where state is stored generally depends on
what type of information you store. In a typical e-commerce application, session identifiers are
often kept on the client as cookies, whereas more detailed information, such as shopping cart
contents, are kept in the database.
The stateless nature of COM+ requires that we construct components to have only methods—
no properties. Furthermore, this limitation implies that all data used by a component must
be received as arguments to the methods and that each method must execute a complete
COM+ Application Fundamentals
97
CHAPTER 4

transaction unto itself. All these design requirements are dictated by COM+’s activation/deacti-
vation features.

Key Principle
If you create a method in a component intended for use under COM+, be sure to pass
all arguments by value through the ByVal keyword. Because ByVal arguments are
passed as a copy of the original data, they are much more efficient in distributed
applications.

QUICK CHECK 4.2

Investigating Object State


1. By using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 04\Quick Check 4.2. This directory contains a project you can use
to investigate state management.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 4.2. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Open the project named stateful.vbp in Visual Basic. This DLL contains a class mod-
ule named Customer. The Customer class contains only a single property for the cus-
tomer’s name.
4. Compile the DLL project and close Visual Basic. 4
5. Create a new COM+ application in the Component Services explorer named State. Install

FUNDAMENTALS
APPLICATION
the compiled component into the new COM+ application.

COM+
6. Expand the tree view until you locate the two methods for the Name property. One
method is Property Get; the other is Property Let. Figure 4.12 shows how they appear
in the Component Services explorer.
7. Locate the file frontend.hta. HTA files are special files that use Dynamic HTML
(DHTML) but don’t run in a browser. Instead, they run inside a window. These file types
are excellent for intranet applications because they don’t have the same security restric-
tions as a browser. If you double-click the file, it will run as shown in Figure 4.13.
Understanding COM+ Applications
98
PART I

FIGURE 4.12
Access the Name properties.

FIGURE 4.13
An HTA front end.

8. This front end will allow you to set and return a value for the Name property. Try it out.
You will find that initially everything seems just fine. You should be able to save state
within the object.
9. Use the Component Services explorer to enable the Auto Done feature for Property Let
and Property Get. This will allow COM+ to deactivate the object between calls to bet-
ter manage resources.
10. Close the front end and restart the application. Try to save the customer name again.
What happens? This time you shouldn’t be able to maintain state in the object.

When it comes to managing state, the only way you can keep stateful information in a COM+
component is to prevent it from being deactivated. However, preventing deactivation means
that precious resources are being used to maintain the stateful component. This doesn’t mean
that you should never create a stateful component, but you must have strong reasons for doing
so. The problem with COM+, however, is that the Auto Done feature isn’t enabled by default.
This means that objects aren’t properly deactivated unless you take positive steps to ensure it.
In this case, ignorance alone can result in an application that doesn’t scale well.
COM+ Application Fundamentals
99
CHAPTER 4

The ObjectControl Interface


When first explained, all this creating and destroying can seem a little confusing. After all, we
can’t really see the resource recycling. COM+, however, offers you a way to gain notification
in your business object when it’s activated or deactivated. This additional control comes in the
form of a special interface known as ObjectControl. The ObjectControl interface has three
methods: CanBePooled, Activate, and Deactivate.
The CanBePooled method notifies COM+ if your object can do true object instance pooling. If
your object returns True when COM+ calls this method, COM+ will use object instance pool-
ing to manage your business object. If you remember, however, earlier in this book I stated
emphatically that Visual Basic components don’t support object instance pooling. Instead,
COM+ simply creates and destroys instances with each client call. So what good is the
CanBePooled method? Microsoft has provided CanBePooled for forward compatibility.
Microsoft has promised true object instance pooling for Visual Basic components under ver-
sion 7.0. Objects that implement the CanBePooled method will easily take advantage of pool-
ing without rewriting when Visual Basic supports it. For now, CanBePooled is optional, and
returning True from the method won’t do anything.

NOTE
Even though returning True from the CanBePooled method currently has no effect on
your components, you should be careful about adding this method thoughtlessly to
your classes. Visual Basic doesn’t currently support object pooling because the apart-
ment threading model is ill suited to handle the concurrency issues raised by pooling.
To successfully pool, an object must support the thread-neutral apartment model
(TNA).
4

FUNDAMENTALS
APPLICATION
The Activate and Deactivate methods are much more useful and interesting than the

COM+
CanBePooled method. Activate and Deactivate are called by COM+ whenever an object is
taken out of or returned to the object pool. The Activate method is called whenever an object
is removed from the object pool and assigned to a client. Deactivate occurs when the object is
returned to the pool. However, because Visual Basic doesn’t really support pooling, these
methods currently fire when an object is created or destroyed. This means that Activate and
Deactivate are essentially identical to Initialize and Terminate. Once VB implements true
pooling, the Initialize and Terminate events will no longer fire for each client call as they
do now. Objects will call Initialize only when they are started the first time and Terminate
only when the complete application is shut down. Under those circumstances, Activate and
Deactivate become critical substitutes for Initialize and Terminate.
Understanding COM+ Applications
100
PART I

By using these methods, you can perform special work when your object is activated or deacti-
vated as well as track the life of the object. Activation and deactivation are tracked on a per-
client basis. Therefore, the Activate and Deactivate events will always fire in pairs for a
given client.

QUICK CHECK 4.3

The ObjectControl Interface


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 04\Quick Check 4.3. This directory contains a project you can use
to investigate the ObjectControl interface.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 4.3. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Open the project named pool.vbp in Visual Basic. In the Pool project, locate the class
module named Test and open its code window. The code window should be empty
except for an Option Explicit statement.
4. Class Test will implement the ObjectControl interface to receive Activate and
Deactivate notifications from COM+. In the [General][Declarations] section of class
Test, add the following code to use the ObjectControl interface:
Implements COMSVCSLib.ObjectControl

5. To implement the ObjectControl interface, select it from the object box in the code win-
dow. When you do, the procedure box will display the three methods: Activate,
CanBePooled, and Deactivate. Add these three methods to class Test.

6. The CanBePooled method simply returns a Boolean value indicating whether the object
supports pooling. Because Visual Basic components don’t support the TNA threading
model, we simply return False from this method:
ObjectControl_CanBePooled = False

7. When the Activate and Deactivate methods are called, we simply use the logging
capability of the App object to write the event out to a log file. In this way, we can keep
track of the life of an instance. Add code to both the Activate and Deactivate methods
to write to a log file. The following code shows the completed methods after you add the
code:
Private Sub ObjectControl_Activate()
App.StartLogging App.Path & “\pool.log”, vbLogToFile
App.LogEvent “COM+ Test Object Activated!”
End Sub
COM+ Application Fundamentals
101
CHAPTER 4

Private Sub ObjectControl_Deactivate()


App.StartLogging App.Path & “\pool.log”, vbLogToFile
App.LogEvent “COM+ Test Object Deactivated!”
End Sub

8. This exercise shows how the ObjectContext affects the life cycle of an instance. To do
this, add a method to the class that won’t use the Auto Done feature. This will prevent
COM+ from deactivating the object. Add the following code to class Test:
Public Function KeepAlive() As String

‘This function does not


‘release the business object
KeepAlive = “Help! I can’t deactivate!”

End Function

9. When creating methods that allow deactivation, you will use the Auto Done feature. Add
the following code to create a method that we will use to allow deactivation:
Public Function Release() As String

‘This function uses Auto Done


Release = “I’m deactivating! Check the log file!”

End Function

10. Compile the DLL project and close Visual Basic.


11. Create a new COM+ application in the Component Services explorer named Pool. Install
the compiled component into the new COM+ application.
12. Expand the tree view until you locate the Release method. By using the property sheet,
enable the Auto Done feature for this method.
4

FUNDAMENTALS
13. After you set up the package and component, run the frontend.hta file by double-click-

APPLICATION
COM+
ing it. This will allow you to call the methods of the component.
14. Start by calling the KeepAlive method. You should get a message box. At this point,
locate and open the log file pool.log. This file will contain a single entry indicating that
the Activate method has fired, but the Deactivate method hasn’t. This means that the
object is still alive and using resources. This is bad.
15. Now call the Release method. When you receive a return value, open the pool.log file
again. This time, notice that both Activate and Deactivate fired. This means that the
object instance existed for the minimum amount of time necessary to process your
request. This is good.
Understanding COM+ Applications
102
PART I

Managing Shared Properties


Although I’ve gone to great length to explain the pitfalls of stateful components in a distributed
application, sometimes you simply require the ability to retain state in the middle tier. For
these times, COM+ provides a facility for maintaining state across the entire application known
as the Shared Property Manager (SPM).
The Shared Property Manager is a separate facility of COM+ for use with stateful information
in the business layer. The Shared Property Manager allows you to create property groups that
can subsequently contain individual property data. By using this hierarchical scheme, develop-
ers can store and share state information within components in the same COM+ application.
The Shared Property Manager creates a sort of global variable that all clients can easily access
by using a specific application. The Shared Property Manager consists of three objects in a
hierarchy: SharedPropertyGroupManager, SharedPropertyGroup, and SharedProperty.
Figure 4.14 shows the SPM object model.

SharedPropertyGroupManager
SharedPropertyGroups
SharedProperty

FIGURE 4.14
The Shared Property Manager can be used to maintain application state.

SharedPropertyGroupManager
The topmost object in the hierarchy, SharedPropertyGroupManager, is considered a resource
dispenser. Just like the resource dispensers for ODBC and OLEDB,
SharedPropertyGroupManager allows resources to be shared among many clients. In this case,
the clients share data. SharedPropertyGroupManager properly manages concurrency issues
allowing for locking data when it’s being changed by a client. To handle these concurrency
issues properly, components that want to share data must be placed within the same package.
Never make a call from one package to another and attempt to share state.

SharedPropertyGroup
SharedPropertyGroup is created through the use of the CreatePropertyGroup method of the
SharedPropertyGroupManager object. This object is used to define a group of shared data.
This object doesn’t represent the actual shared data, but rather a logical grouping of related
data.
COM+ Application Fundamentals
103
CHAPTER 4

SharedProperty
The SharedProperty object actually contains the shared data. This object is returned from the
CreateProperty method of the SharedPropertyGroup object. Once this object is created, you
can use it to read and write data shared by objects in the same package.
Because no calling client knows for sure whether another client has already created this prop-
erty, each call to SharedProperty is treated as though it were the first call. In this way, the
CreateProperty method of SharedPropertyGroup is always executed. The second argument
of the CreateProperty method is a Boolean that will be True if SharedProperty already
exists. Components use this returned value to determine whether the value of SharedProperty
should be initialized or updated.

QUICK CHECK 4.4

The Shared Property Manager


1. By using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 04\Quick Check 4.4. This directory contains a project you can use
to investigate the SPM.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 4.4. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Open the project named sharedproperty.vbp in Visual Basic. This DLL contains a class
module named Count. This class contains a single method called GetUserNumber. This
method will use a global variable to track the number of people who use the application. 4
The following code shows the function definition as it exists when you open the project:

FUNDAMENTALS
APPLICATION
Public Function GetUserNumber() As String

COM+
‘Variables
Dim blnExists As Boolean

‘***Start Adding Code Here!***

‘Return Value
GetUserNumber = “You are client no. “ & objProperty.Value
End Function

4. Within this function, you will add the code to create a shared property. Add your code
into the method at the point where the comment Start Adding Code Here! designates.
Understanding COM+ Applications
104
PART I

This code creates a shared property. Start by adding the following code to create a
SharedPropertyGroupManager object:
Dim objManager As COMSVCSLib.SharedPropertyGroupManager
Set objManager = New COMSVCSLib.SharedPropertyGroupManager

5. Once SharedPropertyGroupManager is created, you can create SharedPropertyGroup.


This is done by calling the CreatePropertyGroup method. In this method, you can spec-
ify arguments that determine the nature of the locking. You can also specify when the
shared property values are destroyed. Add the following code to lock the property when-
ever it is accessed and destroy the values when the package is shut down:
Dim objGroup As COMSVCSLib.SharedPropertyGroup
Set objGroup = objManager.CreatePropertyGroup(“Users”, _
LockSetGet, Process, blnExists)

6. Once the property group exists, you can use it to create the property. The
SharedProperty object is always created as though it were the very first time. The
CreateProperty method returns a True value to the second argument if the property
already exists. In this way, no client has to worry about whether another client has
already created the property. Add the following code to create the new property and set
its value:
Dim objProperty As COMSVCSLib.SharedProperty
Set objProperty = objGroup.CreateProperty(“Number”, blnExists)

‘Set Property
If Not blnExists Then objProperty.Value = 0
objProperty.Value = objProperty.Value + 1

7. Compile the DLL project and close Visual Basic.


8. Create a new COM+ application in the Component Services explorer named Shared.
Install the compiled component into the new COM+ application.
9. Expand the tree view until you locate the GetUserNumber method. By using the property
sheet for the method, set Enable the Auto Done feature.
10. Now locate and run the file frontend.hta. This file will access the Shared property and
increment it each time the file is run. Run several copies to view how the property is
incremented. Figure 4.15 shows the results.
COM+ Application Fundamentals
105
CHAPTER 4

FIGURE 4.15
These pages count the users of the application.

EXERCISE 4.1

A Simple Tiered Application


Now that I’ve presented the fundamental concepts necessary to utilize COM+ applications, you
can begin to use them. In this exercise, you will create a simple application that allows you to
purchase a product through a Web site. We will build considerably on the ideas of e-commerce
throughout the book, but this exercise is designed to whet your appetite.
Creating the COM+ Application
Step 1
By using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 04\Exercise 4.1. This directory contains some partially completed pro-
4
ject files.

FUNDAMENTALS
APPLICATION
Step 2

COM+
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
4.1. Copy the contents from the CD-ROM directory into the new directory you just created.

Step 3
Open the project named taker.vbp in Visual Basic. This project is a COM+ component that
uses the SPM to provide a unique customer ID as well as a method to write completed orders
to a text file.

Step 4
Locate the GetCustomerID function. In this function, add the following code to generate the
Customer ID for our online store:
Understanding COM+ Applications
106
PART I

Dim objManager As COMSVCSLib.SharedPropertyGroupManager


Set objManager = New COMSVCSLib.SharedPropertyGroupManager

Dim objGroup As COMSVCSLib.SharedPropertyGroup


Set objGroup = objManager.CreatePropertyGroup _
(“Customers”, LockSetGet, Process, blnExists)

Dim objProperty As COMSVCSLib.SharedProperty


Set objProperty = objGroup.CreateProperty(“Number”, blnExists)

‘Set Property
If Not blnExists Then objProperty.Value = 0
objProperty.Value = objProperty.Value + 1

‘Return Value
GetCustomerID = objProperty.Value

Step 5
After an order is taken, it will be written out to a text file for fulfillment. Add the following
code to the WriteOut method to create the final text file:
With App
.StartLogging App.Path & “\orders.log”, vbLogToFile
.LogEvent Now
.LogEvent lngCustomer
.LogEvent lngQuantity
End With

Step 6
Compile the completed DLL. Add the component to a new COM+ application named Simple
Orders. In the Component Services explorer, enable the Auto Done feature for both the
GetCustomerID and WriteOut methods.

Creating the Web Front End


Throughout the book, I use Visual InterDev to create Web sites for our COM+ applications. In
most of the exercises, I assume that you know how to properly create a Web project in Visual
InterDev. For those who might need help, I create this project in detail.

Step 7
Start Visual InterDev 6.0 and select to create a new Web project. Choose to create the project
in the directory COM+\Exercise 4-1. Give the new project the name SimpleOrders. When you
select to create a new Web site, Visual InterDev starts the Web Project Wizard.
COM+ Application Fundamentals
107
CHAPTER 4

Step 8
In the first step of the wizard, you must select the server on which the project is to be built.
You can choose any server that you have rights on, but I generally assume that you are build-
ing on the local machine. In this case, you should simply specify the server name as
localhost (see Figure 4.16).

FIGURE 4.16
Select the server on which the Web site will be built.

Step 9
In step 2 of the wizard, select to create a new Web application. Visual InterDev will suggest a
default name (see Figure 4.17). Accept the name SimpleOrders.

FUNDAMENTALS
APPLICATION
COM+

FIGURE 4.17
Give the new Web application a name.
Understanding COM+ Applications
108
PART I

Step 10
The next two wizard steps ask if you want to apply a layout or a theme. Layouts supply navi-
gational features to your site automatically. Themes provide graphics you can use with the site.
In this project, don’t select either a layout or a theme. Just click the Finish button and Visual
InterDev will create the site.

Step 11
After the new Web project is created, add the files default.asp, cart.asp, order.asp, and
toolbar.htm to the project. These Web pages work together to create and manage a simple
shopping cart for the project.

Step 12
Open the file default.asp in Visual InterDev. This page is a frameset that acts as a host for
the other pages. Because the frameset is always loaded in the browser, this project uses the
frameset page to remember the contents of the shopping cart.
To remember the contents, we will use client-side JavaScript variables contained in the
default.asp page. We will write out the initial values in ASP code. This interesting technique
uses ASP to create JavaScript code. Add the following code to default.asp in the area identi-
fied within the template:
Response.Write “<SCRIPT>” & vbCrLf
Response.Write “var customerID = “ & lngCustomerID & “;” & vbCrLf
Response.Write “var quantity = 0;” & vbCrLf
Response.Write “</SCRIPT>” & vbCrLf

Step 13
Quantities in the cart are increased or decreased from the toolbar.htm page. This page uses
client-side JavaScript to access the variables defined in default.asp. After the quantities are
adjusted, you can place your order using this page. Add the following JavaScript functions to
the toolbar.htm page where indicated by the template:
function increase(){
var myParent = document.frames.parent
myParent.quantity++;
myParent.frames(“Cart”).navigate(“cart.asp”);
}

function decrease(){
var myParent = document.frames.parent
myParent.quantity—;
if(myParent.quantity<0)
myParent.quantity=0;
myParent.frames(“Cart”).navigate(“cart.asp”);
}
COM+ Application Fundamentals
109
CHAPTER 4

function order(){
var myParent = document.frames.parent
myParent.frames(“Cart”).navigate _
(“order.asp?ID=” + myParent.customerID _
+ “&Quantity=” + myParent.quantity);
}

Step 14
After the code is complete, you should be able to run the project. Adjust the quantities in the
cart and then place an order. When you are done, examine the text file to ensure that your
order was placed successfully. Figure 4.18 shows the final project.

4
FIGURE 4.18

FUNDAMENTALS
APPLICATION
A simple store that uses COM+ components.

COM+
PART
Data Services
II
IN THIS PART
5 Accessing Data with COM+ 113

6 COM+ Data Components 149

7 COM+ Transactions 181


Accessing Data with COM+ CHAPTER

5
IN THIS CHAPTER
• OLEDB Session Pooling 114

• Understanding Data Transportation 123

• XML 134

• Updating Records 142


Data Services
114
PART II

Regardless of the architectural structure of a business application, data access always forms the
foundation on which you build. This is no different in COM+ applications. However, COM+
demands more than just a casual understanding of data access techniques. Truly scaleable
applications require planning and implementation that reflects a mastery of data access.
This chapter examines the advanced knowledge necessary to successfully build COM+ applica-
tions. I assume that you have some familiarity with OLEDB technology and Microsoft Active
Data Objects (ADO), so you should know the object model and have used ADO in some type
of application before reading this chapter. This will allow us to focus on key aspects of ADO
that are important to our architecture. In particular, we will examine how database connections
can be pooled for increased efficiency, and how records can be transferred between the various
tiers of a COM+ application.

OLEDB Session Pooling


Chapter 4 discussed how COM+ activates and deactivates objects to achieve efficient memory
usage. In this discussion, I noted that COM+ pools components that use the thread-neutral
apartment (TNA) model. Although Visual Basic doesn’t currently support this model, I showed
that pooling can allow COM+ to use memory more efficiently by avoiding the overhead of
repetitive resource allocation.
The idea of avoiding resource allocation is a key concept in the design of scalable systems and
applies to all resources—not just memory. In particular, the pooling of database connection
resources can significantly improve a system’s overall efficiency by avoiding the costly process
of repeatedly connecting to a database. COM+ and ADO 2.5 work together to efficiently man-
age database connections through a process known as session pooling.
Database connection pooling isn’t a new concept. In the past, Open Database Connectivity
(ODBC) data access drivers often supported the concept of leaving a connection open inside a
pool. Session pooling accomplishes the same essential function, but it pools objects instead of
simply connections.
Session pooling begins whenever a database connection is made through the ADO Connection
or Recordset objects. Calling the Open method in either object causes a database connection to
be made. Data may then be retrieved by using the objects and the associated database connec-
tion may be closed. However, if session pooling is enabled, the database connection won’t
actually close. Instead, the connection is pooled in the form of a “data source proxy” object
(DPO). The DPO can subsequently be used by OLEDB when an application creates another
Connection or Recordset object. The application might think it’s getting a new connection, but
under the covers, the DPO is used to make the connection. Figure 5.1 shows a conceptual dia-
gram of this process.
Accessing Data with COM+
115
CHAPTER 5

Internet Client

Internet Client
ActiveX Data Objects
Win32 Client

All clients are coded as if


they each had a unique DPO objects exist in
connection. several different pools
managed by OLEDB

SQLOLEDB Provider

SQL
Server

FIGURE 5.1
Session pooling reduces the overhead of connecting to a database.

Although OLEDB does the session pooling work for you, you can affect several aspects of the
process. How you request access to the database directly affects the number of unique connec-
tion pools maintained by OLEDB. You can also tune the system by configuring the amount of
time any DPO stays in the pool.

Controlling the Number of Pools


OLEDB maintains more than just a single pool of DPO objects. The number of individual
pools maintained are affected by the number of microprocessors on your system and by the
number of unique credentials used to access the database. The formula used by OLEDB to
establish the pools is as follows:
N = C(P+1)
where
• N is the number of unique DPO pools established.
• C is the number of unique credentials used to access the data.
• P is the number of processors. 5
ACCESSING DATA

Controlling the number of pools used by the system is critical to the overall efficiency of the
WITH COM+

pooling process. If you create a new pool for each user of the application, DPO objects can be
removed from the pool and destroyed before they are accessed again. This is because, by
default, DPO objects are removed from the pool and destroyed if they aren’t used within 60
seconds. Therefore, you want to minimize the number of pools created by OLEDB.
Data Services
116
PART II

Examining the formula for pool creation, we can see that the simplest way to minimize the
number of pools is to minimize the number of unique sets of access credentials. The phrase
access credentials refers to more than just the username and password. In this case, access cre-
dentials are a combination of Windows 2000 log-in credentials, database access credentials,
and the database being accessed. If any of these three things change, the credentials are
deemed to change and a new pool is created.
Defining credentials in this way makes perfect sense because pooling connections implies a
certain security risk. Connections opened by system administrators, for example, retain full
permissions even after the DPO is pooled. If only a single pool existed, a system administrator
connection might be given to someone seeking access to the database across the Internet.
Imagine the possible results of such a scenario. Because efficiency demands a small number of
pools and security demands limited permissions, we need to carefully examine the characteris-
tics we assigned to pooled connections.
The first aspect to consider is the Windows 2000 login credentials. Because of the design of
our COM+ applications, we will see that data access is generally performed directly by a
COM+ component. We also know that a COM+ component can be directed to run under the
security credentials of any user in the Active Directory. Therefore, we normally establish a sin-
gle account in Active Directory for our COM+ components. This account is given just the per-
missions necessary to perform its functions, and then the COM+ application is assigned to the
user. Figure 5.2 shows the property settings of a COM+ application, set to a common user.

FIGURE 5.2
Use a common user identity for every COM+ application.

The next aspect to consider is the SQL Server login credentials. If you use integrated security,
the SQL Server login will be the same as the Windows 2000 login. However, if you use stan-
dard security, you will want to set up an account in SQL Server with access to the database
that allows only the minimum required permissions on the target database. You can check the
security setup in the properties dialog box (see Figure 5.3) for your server in the SQL Server
Enterprise Manager.
Accessing Data with COM+
117
CHAPTER 5

FIGURE 5.3
Standard security requires a separate account to be created.

Finally, even if you use the same Windows 2000 account and the same SQL Server account, a
new pool will be created if you access a different database. Again, this is sensible, but worth
recognizing when you are tracking your application’s performance, which can easily be done
through Performance Monitor (see Figure 5.4). Performance Monitor has a counter for SQL
Server connections that is invaluable in determining whether your application is pooling con-
nections as expected.

Tuning Session Pooling


For session pooling to be of any use, it must be enabled for the OLEDB provider you want to
use. Generally, session pooling services are available for providers when you install them.
However, you can configure the availability through Registry settings or arguments in your
connection strings.
Configuring the Registry requires you to locate the entry for your particular OLEDB provider.
Each provider is identified by a globally unique identifier (GUID) and is located at the key
HKEY_CLASSES_ROOT\CLSID\{clsid}. Of course, no one knows what the GUID is for a particu-
lar provider, so how do you find the entry? The answer is to search the HKEY_CLASSES_ROOT
hive using the REGEDIT utility. In this utility, search for keys containing the words OLE DB 5
Provider. This will turn up all the entries for the OLEDB providers installed on your system.
ACCESSING DATA
WITH COM+

Figure 5.5 shows REGEDIT and the search dialog box.


Data Services
118
PART II

FIGURE 5.4
Use Performance Monitor to track database connections.

FIGURE 5.5
Search the Registry for OLEDB provider information.
Accessing Data with COM+
119
CHAPTER 5

At the root of the entry for the OLEDB provider, you will find a setting named
OLEDB_Services. This setting determines whether session pooling is available for this provider.
To enable session pooling, the setting should be 0xFFFFFFFF. This enables all OLEDB ser-
vices, including pooling.
OLEDB Services can also be enabled through the connection string you use in code. When
creating a connection string for an ADO Connection or Recordset object, you can use the argu-
ment OLE DB Services=-1 to enable session pooling. This argument is unnecessary if the
Registry setting already enables pooling, which is the default.
Although session pooling is enabled by default, you might want to tune it by changing the time
that DPO objects are allowed to stay in the pool. By default, DPO objects are removed from
the pool after 60 seconds. This setting can be changed, however, by modifying the Registry for
the particular OLEDB provider. Under the same key in which session pooling is enabled, you
can add a setting to change the timeout value. By default, this value doesn’t exist, so you will
have to add it manually. The name of the setting to add is SPTimeout. The value for the setting
should be a DWORD containing the number of seconds for the new timeout value. Figure 5.6
shows the Registry entry modified for the SQLOLEDB provider.

5
ACCESSING DATA

FIGURE 5.6
WITH COM+

Add the SPTimeout setting to tune session pooling.


Data Services
120
PART II

Selecting an appropriate value for the timeout depends on the number of users in your applica-
tion and how many pools are created. The whole point of session pooling is to avoid the over-
head of creating a new connection. The process does you no good if application users don’t
strike the database before the DPO objects are destroyed. Therefore, you need to tune the time-
out value to be twice the average time between database connections. If a client hits the data-
base every minute, a timeout of 120 seconds is appropriate.
In many applications, session pooling might not do any good at all. After all, if you have just a
few users on the system who access the database once or twice per day, what would be the
point of an eight-hour timeout? Session pooling is really intended for scalable systems with
large numbers of users. Small systems will almost always have to suffer some connection over-
head and associated loss of efficiency.

QUICK CHECK 5.1

Session Pooling
1. By using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 05\Quick Check 5.1. This directory contains a project you can use
to investigate OLEDB session pooling.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 5.1. Copy the contents from the CD-ROM directory into this new
directory.
3. Open the project named dispenser.vbp in Visual Basic. This DLL contains a method
that simply connects to and disconnects from the pubs database.

NOTE
The connection string in this example assumes that the SQL Server is running locally
and is set up for standard security. If your installation is different, you might have to
modify this code.

4. Compile the DLL project and close Visual Basic.


5. Create a new COM+ application in the Component Services explorer named Session
Pooling. Install the compiled component into the new COM+ application.
6. Expand the tree view and locate the Connect method in the explorer. Open the property
sheet for the method and enable the Auto Done property.
Accessing Data with COM+
121
CHAPTER 5

7. Now locate the file client.hta. This file calls the COM+ component and requests data-
base connections. Double-click this file to start the application. Figure 5.7 shows the
page.

FIGURE 5.7
Use this page to request database connections.

8. The HTA page allows you to set a value for the timeout and to request a new database
connection. Start by entering a value of 60 for the timeout and clicking the button on the
page. You should get a message telling you the timeout has been changed.
9. Start Performance Monitor by typing PERFMON at the command line. When Performance
Monitor starts, no counters will be running. You need to add a counter by clicking the
+ sign on the toolbar. Figure 5.8 shows Performance Monitor’s Add Counters dialog box.

5
ACCESSING DATA
WITH COM+

FIGURE 5.8
Add a new counter to the Performance Monitor.
Data Services
122
PART II

10. From the Performance Object drop-down list, select to add SQL Server: General
Statistics. Then select to add the User Connections counter and click Add. Performance
Monitor will start to track the number of connections made to SQL Server.
11. On the HTA page, request a new connection. You should see Performance Monitor indi-
cate that you have a new connection. Click the button again and you should get a second
connection. This behavior is expected based on the pooling formula we examined earlier.
12. Request several more connections. Notice that the connection counter never rises above
two. This is because all the connection requests are now being fulfilled by pooled DPO
objects.
13. Stop requesting connections and watch the monitor. After 60 seconds, you should see
both connections disappear. This is the timeout causing the DPO objects to be destroyed.
Try adjusting the timeout value and tracking the results by using Performance Monitor.
Figure 5.9 shows a typical trace for a 30-second timeout.

FIGURE 5.9
Change the timeout setting and view the results.
Accessing Data with COM+
123
CHAPTER 5

Understanding Data Transportation


Consider the theoretical set of three tiers that make up the standard Windows DNA application.
We are all well aware that the purpose of creating data, business, and user services layers is to
separate, or partition, functionality to improve maintainability. However, the difficulty of mov-
ing from the theoretical to the practical lies in understanding how the various tiers will com-
municate and cooperate to create a system. In particular, a properly designed system must have
a standardized mechanism for moving a data set from data services up to user services as well
as operating on the data set within tiers to apply rules.
Moving data between tiers in the application requires some sort of “container” to hold the data.
This container can take many forms such as a delimited string or a Recordset, but the container
must be standard throughout the system. The container is a sort of currency, or medium of
exchange, with which the tiers can communicate. In this section, we examine the various ways
to transport data between tiers and modify that data within a tier. Figure 5.10 shows a concep-
tual drawing of data being transported between the data and business services tiers.

Business Services Data Services

3. The "container" is 2. The "container is 1. Individual records from


unpacked so the data can transported from one layer the database must be
be operated on. to the next. returned and packed into
a "container" for
transport.

FIGURE 5.10
Data must be transported between tiers and operated on within tiers.

Understanding Cursors
Establishing a workable data transportation scheme requires intimate knowledge of ADO cur-
sors. Creating the correct cursor is a matter of setting the proper combinations for the 5
CursorLocation, CursorType, LockType, and CacheSize properties. If you are unfamiliar with
ACCESSING DATA
WITH COM+

the various cursors supported by ADO, you will have difficulty designing applications that per-
form well. The following sections examine the values for the CursorType property, followed
by appropriate settings for the other properties.
Data Services
124
PART II

adOpenDynamic
When you set the CursorType property of an ADO Recordset object to adOpenDynamic, you
open records with a dynamic cursor. The dynamic cursor has the most features of any cursor in
ADO. By using a dynamic cursor, you can scroll forward and backward through the recordset.
You can also use bookmarks if they are supported by the OLEDB provider you are using.
Dynamic cursors also reflect additions, deletions, and modifications made to the underlying
database.
The problem with the dynamic cursor is that all its functionality comes at a tremendous price.
The dynamic cursor is the poorest performing cursor of all. Couple this type of cursor with
pessimistic record locking, and you have a recipe for disaster. You should never use this cursor
type in any application. You should not use it with COM+ because the poor performance will
destroy scalability.

adOpenKeyset
When you set the CursorType property of an ADO Recordset object to adOpenKeyset, you
open records with a keyset cursor. The keyset cursor is similar to the dynamic cursor except
that it doesn’t reflect additions to the database in your cursor. It does, however, still reflect
edits from other users. This type of cursor is less expansive than a dynamic cursor; however,
it’s still unusable for COM+ applications.

adOpenStatic
When you set the CursorType property of an ADO Recordset object to adOpenStatic, you
open records with a static cursor. A static cursor allows you to view and edit records, but it
doesn’t reflect any changes, additions, or deletions made by other users of the database. This
cursor is a viable option for COM+ applications. We can combine this type of cursor with the
connection pooling strategy outlined earlier in the chapter to produce good results in COM+.

adOpenForwardOnly
When you set the CursorType property of an ADO Recordset object to adOpenForwardOnly,
you open records with a cursor that can only move forward through the recordset. This is the
default cursor type in ADO. This cursor type is an excellent cursor for scalable applications
because we can use it to rapidly retrieve and store data in a transport.

Allowable Combinations
ADO supports many different combinations of properties that affect cursor performance. These
combinations are often confusing to developers, and selecting the wrong combinations can eas-
ily destroy performance. We recognize two acceptable combinations of properties for COM+
applications. These two combinations go by the names firehose cursor and disconnected
recordset.
Accessing Data with COM+
125
CHAPTER 5

Firehose Cursors
A firehose cursor is a rapid-delivery, forward-only recordset. It rapidly streams data out of the
database with very little overhead. Firehose cursors are high-speed, no-frills recordsets. To cre-
ate one, you must set the properties of the ADO Recordset appropriately before running the
query. Firehose cursors require you to define a forward-only, server-side cursor with a cache
size of 1. A firehose cursor requires the following settings:

Property Value
CursorLocation adUseServer
CursorType adOpenForwardOnly
LockType adLockReadOnly
CacheSize 1

When you use a firehose cursor in COM+, you typically use it to rapidly fill a container with
data. This container can be a string, an array, or a custom object. I will discuss the particular
options in the next section. The point is that you have rapidly transferred the data from the
database and into another structure so that your database connection can be pooled.

Disconnected Recordsets
An alternative to the firehose cursor is the disconnected recordset. The disconnected recordset
is a set of records that are retrieved from the database into a standard ADO Recordset object,
but after the query is run, the Recordset object disassociates itself from the open connection.
This creates a recordset that can be sent to a client as the return value of a function. The advan-
tage of this type of object is that you can use all the features of a Recordset object without
maintaining an open database connection. Just like the firehose cursor, the disconnected
recordset isn’t a true cursor and has very little overhead. I discuss the particulars of using this
cursor type later in the next section. A disconnected recordset requires the following settings.

Property Value
CursorLocation adUseClient
CursorType adOpenStatic
LockType adLockBatchOptimistic

Understanding Transports and Payloads


To communicate the concepts inherent in moving data sets around a tiered system, we define 5
two new terms: transport and payload. A transport is the container inside of which we pack
ACCESSING DATA
WITH COM+

data, schema information, and error information. The data, schema, and error information
inside the transport are referred to as the payload. Therefore, we can say that a transport con-
tains a payload.
Data Services
126
PART II

There are many different options for defining transports and payloads. Some designs are purely
object oriented (OO). In these designs, the transport might be an object that contains a set of
different objects constituting the payload. Other designs might not be OO at all. The simplest
transport, for example, is a delimited string. In this case, the string variable is the transport and
the characters of the string make up the payload. Because objects are easier to deal with in
code, OO transports are appealing; however, they are often the poorest performing of the many
options.
Along with object orientation and performance, we are concerned with self-definition. A self-
defined payload is one that contains not only the data, but also a schema definition. Schema
definitions are invaluable because they allow any tier in the application to discover what is in
the payload, which in turn can affect how the data is used. Schemas are like a packing list for a
shipping container.
With the concepts of transport and payload, we will now survey all the different options for
moving data within a tiered system. In this survey, we will be careful to address performance,
object-orientation, and self-definition. In this way, you can decide exactly which mechanism is
right for your application.

Delimited Strings
Delimited strings have the following characteristics:
• Performance: Excellent
• Object-Oriented: No
• Self-Defined: Sometimes
As I indicated earlier, the simplest form of a transport is the delimited string. Delimited strings
are a good choice for performance. However, delimited strings can be hard to deal with
because you must parse them to access the data. This means that you can move the data rapidly
between tiers, but you will have difficulty operating on the data within a tier.
Delimited strings can also be self-defined as in the case of Extensible Markup Language
(XML). XML has the performance characteristics of a delimited string with the capability to
house enhanced information. XML is discussed in detail later in the chapter.
The easiest way to create a delimited string for use as a transport is to invoke the GetString
method of the ADO Recordset. The GetString method takes an existing Recordset and creates
a string, using tabs to separate the columns and carriage returns to separate the rows. This
string can then be sent directly to the caller as a return value from the function.
The GetString method is primarily used to gain maximum transport performance. Therefore,
when you intend to use this transport, you will want to create the lightest possible cursor. The
Accessing Data with COM+
127
CHAPTER 5

appropriate cursor type for the delimited string is the firehose cursor. The good news here is
that the firehose is the default cursor in ADO. Therefore, returning a delimited string can be
very simple. The code in Listing 5.1 shows a function that returns a delimited string.

LISTING 5.1 Returning a Delimited String


Public Function Lookup() As String

Dim objRecordset As ADODB.Recordset


Set objRecordset = New ADODB.Recordset

‘Run Query
objRecordset.ActiveConnection = _
“Provider=SQLOLEDB;Data Source=(local);Database=pubs;UID=sa;PWD=;”
objRecordset.Source = “SELECT pub_name FROM Publishers”

objRecordset.Open

‘Pass string to client


Lookup = objRecordset.GetString

End Function

Because the GetString method of the Recordset object allows you to specify the column and
row delimiter for the string, you can often change the form of the data into something more
recognizable. For example, delimiting the data with <TR> and <TD> tags allows you to create an
HTML stream that can be displayed directly from the return value.

Variant Arrays
Variant arrays have the following characteristics:
• Performance: Poor
• Object-Oriented: No
• Self-Defined: No
Variant arrays were one of the first widely used transports in distributed applications. Variant
arrays use a Variant data type passed into a function by reference. Because the Variant was
passed in by reference, it could be filled with data inside the function and then automatically 5
returned to the calling client when the function completed.
ACCESSING DATA
WITH COM+

The problem with Variant arrays is that they are the single worst choice for a transport. Passing
Variants by reference is one of the most expansive operations you can perform because the
Data Services
128
PART II

Variant must be marshaled between two machines to make the initial function call and then
marshaled again on the return.
Marshaling is a process performed by COM+ and the operating system that moves complex
data types like variants or objects between machines and processes. Normally when an object
or Variant is passed within the same process on the same machine, COM+ can simply pass a
reference to the variable—not the entire variable. However, when you move an object or
Variant between machines, the reference from one machine isn’t valid on the other. Therefore,
a copy of the data must be moved to the other machine’s memory before it can be used. This is
the expansive part of the process, which is doubled when the Variant or object is passed by
reference.
Nonetheless, many applications have been built successfully with Variant arrays. When you use
a Variant array, you will again use a firehose cursor because you want to transfer the data from
the Recordset and into the array as quickly as possible. After you open the firehose cursor, the
data can be transferred into the array through the GetRows method. The code in Listing 5.2
shows a function that returns a Variant array.

LISTING 5.2 Returning a Variant Array


Public Function Lookup() As Variant

Dim objRecordset As ADODB.Recordset


Set objRecordset = New ADODB.Recordset

‘Run Query
objRecordset.ActiveConnection = _
“Provider=SQLOLEDB;Data Source=(local);Database=pubs;UID=sa;PWD=;”
objRecordset.Source = “SELECT pub_name FROM Publishers”

objRecordset.Open

‘Pass array to client


Lookup = objRecordset.GetRows

End Function

When the client receives the Variant array, we have more trouble. The returned array is simply
a container full of data with no information about the contents. It’s not self-defined. Because
the payload within the array has no schema, the payload definition must be kept somewhere
else. The typical answer to this problem is to define a set of enumerations that tell the client
what’s in the array. This allows the client to use enumerations instead of numbers as the
indexes for the array. If, for example, our Variant array contained information about authors in
the pubs database, we might define the following enumeration:
Accessing Data with COM+
129
CHAPTER 5

Public Enum ArrayFieldsEnum


SSN
FirstName
LastName
Address
City
State
Zip
End Enum

Disconnected Recordsets
Disconnected recordsets have the following characteristics:
• Performance: Good
• Object-Oriented: Yes
• Self-Defined: Yes
Disconnected recordsets are a staple of distributed applications. They are a strong choice for a
transport and offer a nice compromise between performance, object orientation, and self-
definition. This is true because Microsoft has specifically designed the ADO Recordset object
to function as a transport.
Based on my discussion of variant arrays, you might initially conclude that a recordset would
be a poor performer. After all, it’s an object and should therefore suffer from the same mar-
shaling overhead endured by all objects. This, however, isn’t the case. Microsoft has designed
the ADO Recordset object so that it transports between processes in a fundamentally different
way. Unlike standard Visual Basic objects, the Recordset isn’t marshaled when it’s moved
between processes on different computers. Instead, the object and all its data are persisted and
then streamed to the other process.
Moving the Recordset object and its data is accomplished by the OLEDB Persistence Provider
(MSPersist). When a Recordset is moved between processes, the object and the records it con-
tains are converted into a special format known as Advance Data Tablegram (ADTG). This for-
mat creates a high-performance data stream that will move rapidly from one process to
another. When the ADTG arrives at the destination process, MSPersist re-creates the original
Recordset object automatically.
The performance provided by MSPersist, the OO nature of the Recordset, and the schema 5
information provided by the Fields collection make this transport very attractive. The drawback
ACCESSING DATA
WITH COM+

of this transport, however, is that it relies on ADO being present at each tier in the hierarchy.
This means that your entire system will be affected if Microsoft comes out with new data
access technology.
Data Services
130
PART II

Earlier in the chapter, I defined the ADO property settings necessary to create a disconnected
recordset. After you have created the disconnected recordset and run a query, you must disas-
sociate the database connection. This is accomplished by setting the recordset’s
ActiveConnection property to Nothing. Once disassociated, you can freely pass the recordset
as a return value from a function. Listing 5.3 shows how you might run a query in a COM+
component and return a disconnected recordset.

LISTING 5.3 Returning a Disconnected Recordset


Public Function Query () As ADODB.Recordset

Set Query = Nothing

‘Variables
Dim objRecordset As ADODB.Recordset
Set objRecordset = New ADODB.Recordset

‘Run Query
objRecordset.ActiveConnection = _
“Provider=SQLOLEDB;Data Source=(local);Database=pubs;UID=sa;PWD=;”
objRecordset.CursorLocation = adUseClient
objRecordset.CursorType = adOpenStatic
objRecordset.LockType = adLockBatchOptimistic
objRecordset.Source = “SELECT * FROM Publishers

‘Get Data
objRecordset.Open

‘Disconnect Recordset
Set objRecordset.ActiveConnection = Nothing

‘Return the Records


Set Query = objRecordset

End Function

When the disconnected recordset is received by the client, it behaves just like any other record-
set. You can navigate the recordset with MoveFirst, MoveLast, MoveNext, and MovePrevious.
You can edit the data and save the changes locally. You can even add and delete records. The
changes are simply not permanent until you reconnect the recordset to the parent database and
commit the changes.
Accessing Data with COM+
131
CHAPTER 5

Property Bags
Property bags have the following characteristics:
• Performance: Good
• Object-Oriented: Yes
• Self-Defined: No
Using property bags as a transport emerged along with the inclusion of object persistence in
Visual Basic 6.0. Property bag objects can contain an entire instance of any object and convert
that object to a byte array. The byte array can than be moved across process boundaries as a
return value from a function. Once received by a calling client, the byte array is fed back into a
property bag to re-create the object.
In many ways, using a property bag is the same as using MSPersist to pass Recordsets across
process boundaries. The difference is that a property bag can convert any object into a byte
array. The attraction of this approach is that you can build and pass custom objects like cus-
tomer, order, and supplier objects. Because you can actually pass objects that represent busi-
ness entities, many developers feel this approach is the closest to a pure OO application;
however, it can be cumbersome to program and somewhat inflexible.

New Versus CreateObject


When using the property bag approach, you might often find that you are creating
instances of custom objects within the same DLL. This raises the issue of whether to
use the New keyword or the CreateObject function when instancing your objects. This
issue has implications for all objects in your system, so I discuss it here.
Using the New keyword in a COM+ application is acceptable; however, you must be
aware of some limitations. When you create instances with the New keyword and the
creator is in the same DLL as the class being instantiated, Visual Basic creates the
instance through an optimized process known only to VB. This is a problem because
COM+ can’t set up properly when instances are created this way.
The New keyword can be used anytime when the creator is in a different DLL from the
class being instantiated. In this case, the New keyword evokes the normal creation
process and COM+ works just fine. I have seen many developers misunderstand these
limitations. In some cases, development teams have gone through their entire appli-
cation and replaced New with CreateObject. My experience, on the other hand, is that 5
well designed distributed systems generally have no need to create instances of
ACCESSING DATA
WITH COM+

classes within the DLL. They generally are looking for services from a separate
component.
Nonetheless, be aware of this limitation and watch for it in code reviews.
Data Services
132
PART II

Before you can even begin to use this transport mechanism, you must understand how to
achieve object persistence in Visual Basic. Beginning with Visual Basic 6.0, you could create a
persistent object by setting the Persistable property in a class module. The typical scheme is
to create a class module that maps to a business entity and then make the class persistable.
When a class module is designated as persistable, Visual Basic adds three new events to the
class: InitProperties, ReadProperties, and WriteProperties. The class is also now associ-
ated with a PropertyBag object that enables the persistence. The idea here is to save the values
from a recordset into the class properties.
The PropertyBag object can hold the values of the properties in the class to be persisted. To
store values in the PropertyBag, the class must explicitly read and write them to the bag.
Reading and writing properties must occur in the ReadProperties and WriteProperties
events. The code in Listing 5.4 shows how a class module representing an author might man-
age properties with a PropertyBag object.

LISTING 5.4 Managing Properties with a Property Bag


Private Sub Class_ReadProperties(PropBag As PropertyBag)
With PropBag
m_au_id = .ReadProperty(“au_id”)
m_au_fname = .ReadProperty(“au_fname”)
m_au_lname = .ReadProperty(“au_lname”)
m_address = .ReadProperty(“address”)
m_city = .ReadProperty(“city”)
m_state = .ReadProperty(“state”)
m_zip = .ReadProperty(“zip”)
End With
End Sub

Private Sub Class_WriteProperties(PropBag As PropertyBag)


With PropBag
.WriteProperty “au_id”, m_au_id
.WriteProperty “au_fname”, m_au_fname
.WriteProperty “au_lname”, m_au_lname
.WriteProperty “address”, m_address
.WriteProperty “city”, m_city
.WriteProperty “state”, m_state
.WriteProperty “zip”, m_zip
End With
End Sub

Once the object has persistence behavior, a separate PropertyBag can be used to create a byte
array that represents the contents of the property bag. It’s the array that can be transferred
Accessing Data with COM+
133
CHAPTER 5

efficiently across process boundaries. Listing 5.5 shows how the same author object can be
filled from a firehose cursor, changed into a byte array, and transferred to a calling client.

LISTING 5.5 Returning a Byte Array


Public Function GetAuthor(ByVal strSSN As String) As Byte()

‘This function returns a byte array


‘from a property bag

On Error GoTo GetAuthorsErr

Dim objRecordset As ADODB.Recordset


Dim objAuthor As ByteTrans.Author
Dim objBag As PropertyBag

‘Run Query
Set objRecordset = New ADODB.Recordset
objRecordset.Open _
“SELECT * FROM Authors WHERE au_id =’” & strSSN & “‘“, _
“Provider=SQLOLEDB;Data Source=(local);Initial Catalog=pubs;UID=sa;PWD=;” _
, adOpenForwardOnly, adLockReadOnly

‘Create Author object


‘NOTE: Use CreateObject because the are in the same DLL!
Set objAuthor = CreateObject(“ByteTrans.Author”)

‘Fill object from Recordset


With objAuthor
.au_id = objRecordset!au_id
.au_fname = objRecordset!au_fname
.au_lname = objRecordset!au_lname
.address = objRecordset!address
.city = objRecordset!city
.state = objRecordset!state
.zip = objRecordset!zip
End With

objRecordset.Close
Set objRecordset = Nothing
5
‘Put object in Property Bag
ACCESSING DATA
WITH COM+

Set objBag = New PropertyBag


objBag.WriteProperty “Author”, objAuthor
Data Services
134
PART II

LISTING 5.5 Continued


‘Return Byte Array
GetAuthor = objBag.Contents

GetAuthorsExit:
Exit Function

GetAuthorsErr:
Debug.Print Err.Description
Resume GetAuthorsExit

End Function

After the byte array is transferred to the calling client, a new property bag can be used to
reconstitute the original object. This has the effect of allowing you to pass custom objects in
your system without the overhead of marshaling. The following code shows how to re-create
the same author object in the client process:
‘Call Data Layer
bytData = objData.GetAuthor(txtSSN)
objBag.Contents = bytData

‘Re-create Author Object


Set objAuthor = objBag.ReadProperty(“Author”)

Conclusion
We have seen many different mechanisms for transporting data between tiers, and developers
are right to question the available options. The best transport scheme, however, will move data
rapidly between tiers, provide OO access to the data within the tiers, and be self-defined. This
is why the disconnected recordset has been such a great choice. If you are creating an applica-
tion based entirely on Microsoft products, this is an excellent transport.
Disconnected recordsets do have some limitations, however. Most notably, disconnected
recordsets aren’t platform independent. You can’t, for example, send a disconnected recordset
from COM+ to a UNIX system for processing. Furthermore, disconnected recordsets have lim-
ited capability to carry additional user-defined information. For example, you might want to
send user-defined error information with the data payload to indicate that not all the informa-
tion was retrieved correctly. For these reasons, we want to consider XML as a transport.

XML
As stated earlier, XML is really a specialized version of a delimited string. This means that
XML has excellent performance when transferring data between tiers. Because XML is
Accessing Data with COM+
135
CHAPTER 5

cross-platform, it also means that you can use it to send data from your COM+ applications to
any other platform, and XML supports the simple addition of user-defined information. The
only real drawback to XML is that it’s not an OO transport. This means that you must parse
the text within tiers to work with the data.

XML Fundamentals
An incredibly simple way to return XML from a COM+ data object is to use the GetString
method with some special delimiters. I showed earlier in the chapter that you could easily
define an HTML string using this technique, and it’s no more difficult to create XML. The
code in Listing 5.6 shows how to use a firehose cursor and custom delimiters to create an
XML stream that represents the publishers table from the pubs database.

LISTING 5.6 Returning Simple XML


Public Function GetPublishers() As String

On Error GoTo GetPublishersErr

GetPublishers = “”

‘Open Connection
Dim objConnection As ADODB.Connection
Dim objResultset As ADODB.Recordset

Set objConnection = New ADODB.Connection


objConnection.ConnectionString = _
“Provider=SQLOLEDB;Data Source=(local);Initial Catalog=pubs;UID=sa;PWD=;”
objConnection.Open

‘Run Query
Set objResultset = New ADODB.Recordset
Set objResultset.ActiveConnection = objConnection
objResultset.Source = “SELECT pub_name FROM Publishers ORDER BY pub_name”
objResultset.Open

‘Create Return String


Dim strTemp As String
strTemp = “<?xml version=” & Chr$(34) & “1.0” & Chr$(34) & “?>” & vbCrLf
strTemp = strTemp & “<?xml:stylesheet type=” & Chr$(34) & _ 5
“text/xsl” & Chr$(34) & “ href=” & Chr$(34) & _
ACCESSING DATA
WITH COM+

“data.xsl” & Chr$(34) & “?>” & vbCrLf


strTemp = strTemp & “<PUBLISHERS>” & vbCrLf & “<NAME>”
Data Services
136
PART II

LISTING 5.6 Continued


strTemp = strTemp & objResultset.GetString( _
, , vbCrLf, “</NAME>” & vbCrLf & “<NAME>”)
strTemp = strTemp & “</NAME>” & vbCrLf & “</PUBLISHERS>”
GetPublishers = strTemp

‘Close Connection
objResultset.Close
objConnection.Close
Set objResultset = Nothing
Set objConnection = Nothing

GetPublishersExit:
Exit Function

GetPublishersErr:
GetPublishers = Err.Description
Resume GetPublishersExit

End Function

XML knowledge is an integral part of many Microsoft products. In fact, Internet Explorer can
display XML documents directly. This means that the output from the function in Listing 5.6
can be displayed directly in a browser. Figure 5.11 shows the output of the function as it
appears in Internet Explorer.

Notice that in the absence of any additional information, Internet Explorer simply displays the
XML in its raw form. Clearly, this format isn’t acceptable for presentation to a user.
Fortunately, we can direct Internet Explorer to format the data as though it were HTML
through the use of Extensible Stylesheet Language (XSL). XSL is used to transform XML data
into HTML pages. Figure 5.12 shows the same XML page with a style sheet applied.

XSL allows us to transform raw XML data into a format acceptable for viewing. In addition to
presentation, you can use XSL to create any HTML element. This means that you can create
anchor tags, images, and even script blocks. In short, you can create anything you might want
in the final HTML page.
Normally style sheets are created as separate files with XSL extensions. They are then associ-
ated with an XML file by placing a reference to the style sheet within the XML. The following
line in the XML file associates our publisher data with the style sheet data.xsl:
<?xml:stylesheet type=”text/xsl” href=”data.xsl”?>
Accessing Data with COM+
137
CHAPTER 5

FIGURE 5.11
Simple XML in the Internet Explorer.

5
ACCESSING DATA
WITH COM+

FIGURE 5.12
Simple XML with a style sheet.
Data Services
138
PART II

After you associate the XML with a style sheet, you can use the style sheet to change the ren-
dering of the XML. The XSL page conforms to XML rules. The style sheet is really a special-
ized XML file. Each XSL page defines a set of templates used to render the page. The
templates look for key data within the XML page and then plug that data into the page defined
by the style sheet. Listing 5.7 shows the style sheet for our publishers data.

LISTING 5.7 A Simple Style Sheet


<xsl:stylesheet xmlns:xsl=”http://www.w3.org/TR/WD-xsl” _
xmlns:HTML=”http://www.w3.org/Profiles/XHTML-transitional”>

<!-- The template for the page -->


<xsl:template match=”/”>
<HTML>
<HEAD>
<TITLE>XML from ADO</TITLE>
</HEAD>
<BODY>
<CENTER>
<H1>Publishers</H1>
<TABLE BORDER=”1” STYLE=”font-family:arial;font-size:14pt;”>
<xsl:apply-templates select=”PUBLISHERS/NAME”/>
</TABLE>
</CENTER>
</BODY>
</HTML>
</xsl:template>

<!-- The template for the rows -->


<xsl:template match=”NAME”>
<TR><TD><xsl:value-of/></TD></TR>
</xsl:template>

</xsl:stylesheet>

Examine the style sheet listing and locate the <CENTER></CENTER> tags. Notice that between
these tags is defined a set of HTML <TABLE> tags. This table will be used to display the pub-
lishers data. Inside the table, find the following line of code:
<xsl:apply-templates select=”PUBLISHERS/NAME”/>

This XSL tag specifies that the style sheet should look in the associated XML file for the tags
<PUBLISHERS><NAME>. When these tags are found, the style sheet will traverse every <NAME> tag
and format it according to the style sheet. The format for the <NAME> tag is defined at the bot-
tom of the sheet where a new table row is created for each publisher’s name. In this way, an
Accessing Data with COM+
139
CHAPTER 5

HTML table is created for the returned XML data. I discuss XSL in more detail in Chapter 11,
“COM+ and the Internet.”

The Stream Object


Before the release of ADO 2.5, using the GetString method was the only way to create a text
stream of XML. Previous versions of ADO could save data to a file in XML format, but it
wasn’t until ADO 2.5 that we had a reliable and flexible way to return XML data from a com-
ponent as a string. This capability is contained in the new ADO Stream object.
The best way to think of the Stream object is like an in-RAM file system. It reminds me of the
old RAMDRIVE in DOS. The way it works is that you use the Recordset object’s Save method
just as though you were going to save the Recordset to a file, but rather than specify the file-
name, you provide a Stream object. Once the Recordset is stored in the Stream object, you can
return the XML representation of the data as a string by using the ReadText method.
The other benefit of using the Stream object is that it contains a complete schema section for
the XML data. This means data generated by the Stream object is self-defined. The data and
the definition are contained in the same package. Listing 5.8 shows how to use the Stream
object to return the same publisher’s information discussed earlier.

LISTING 5.8 Returning XML with the Stream Object


Public Function GetData() As String

‘Get Records
Dim m_Recordset As ADODB.Recordset
Set m_Recordset = New ADODB.Recordset

m_Recordset.ActiveConnection = _
“Provider=SQLOLEDB;Data Source=(local);Initial Catalog=pubs;UID=sa;PWD=;”
m_Recordset.Source = “SELECT * FROM Publishers”
m_Recordset.Open

‘Persist in Stream
Dim m_Stream As ADODB.Stream
Set m_Stream = New ADODB.Stream

m_Recordset.Save m_Stream, adPersistXML


5
ACCESSING DATA

‘Return XML Stream


WITH COM+

GetData = m_Stream.ReadText

End Function
Data Services
140
PART II

Stream is an incredibly flexible object that allows you to send XML to any component on any
platform. Because the Stream object produces text as an output, you also get excellent perfor-
mance. I stated earlier, however, that delimited strings are difficult to deal with because they
must be parsed to access the data. Although this is still true, you have several options to solve
this problem.
If you are creating a system intended to transfer data across platforms, you will need to use an
XML parser to access the data once it arrives. XML parsers exist for many different operating
systems, but all of them generally work the same way. They provide hierarchical sets of objects
that allow access to the XML data.
On Microsoft platforms, you can use the MSXML component. MSXML is a component that
ships with Windows 2000 and allows you to access the data in any XML file. It works through
a generic set of objects that deal with each XML tag as a “node.” Every XML file is seen as a
hierarchical set of nodes that can be traversed to get the desired data. The top-level object in
the model is DOMDocument, which represents the entire XML file. For nodes within the docu-
ment, you simply use the ChildNodes collection to drill into the data. The following code uses
the MSXML parser to examine the schema section of the XML and determine the number of
fields in the data:
‘Create new XML Document
strXML = m_Data.GetData
Set m_Document = New MSXML.DOMDocument

m_Document.loadXML strXML
m_FieldCount = _
m_Document.childNodes(0).childNodes(1). _
childNodes(0).Attributes.length

The problem with parsing XML data is that you still have to know something about the data
format to get what you want. Notice that in the preceding code, I’ve used hard-coded constants
in the ChildNodes collections. This is very common in applications that use MSXML, but it’s
entirely unmaintainable. I’ve seen many such applications and when I ask the developers how
they know what constants to use, they often reply, “I’ve been working with it so long, I just
know them.” This, of course, is a disaster waiting for the next programmer who has to maintain
the system.
Because of the tedious and unmaintainable coding associated with MSXML, I’m not a propo-
nent of this solution. Instead, I prefer to use the Stream object to convert the XML back into a
Recordset. That’s right, the Stream can not only create XML from a Recordset, but the
Recordset can also be reconstituted from the XML. In this way, you can use the XML just to
gain the benefits of transportation while keeping the Recordset as the internal OO representa-
tion of the data. This is the best of all possible scenarios.
Accessing Data with COM+
141
CHAPTER 5

Hold on! Isn’t this just coming full circle? After all, when I discussed disconnected recordsets
before, I said that the MSPersist provider automatically converts recordsets to the ADTG for-
mat for transportation across processes to maximize performance. Aren’t we doing the same
thing here?
Although it’s true that MSPersist does the transformation for you, we still might want to create
XML manually so that we can easily add user-defined information to the payload. You see,
when MSPersist transfers a Recordset across a process, the Recordset will have <SCHEMA> and
<DATA> sections. But suppose that you wanted an <ERRORS> section to contain system errors. In
this case, you would use the MSXML component to append a new set of nodes to the XML
before it was transferred to the client. Once received, the client would remove the appended
nodes and then reconstitute the Recordset. This is my preferred transport strategy and the one I
will build on as the book continues.

Web Services and SOAP


XML has continued to gain favor in the programming community because of the strengths out-
lined thus far. In fact, the next evolution of this technology will allow Visual Basic developers
not only to transfer data between platforms, but also to actually make procedure calls across
platforms. That’s right, a UNIX front end will be able to call a Visual Basic COM+ component
over the Internet. This is accomplished by using an XML-based remote procedure call known
as the Simple Object Access Protocol (SOAP).
SOAP allows a client to format a procedure call as an XML payload. The fulfilling component
can receive the SOAP request, process it, and return the results as XML. Suppose that you
wanted to call a Visual Basic method named GetAuthorData from your UNIX application. You
could format the request as XML in a fashion similar to the following:
<?xml version=’1.0’ ?>
<methods href=’http://MyApp’>
<method name=’GetAuthorData’ href=’GetAuthorData’>
<request>
<param dt=’string’>111-11-1111</param>
</request>
<response dt=’string’/>
</method>
</methods>

Visual Basic developers will create SOAP-enabled components by using Visual Basic 7.0’s 5
new Web Services feature. Web Services are essentially classes that know how to open a SOAP
ACCESSING DATA
WITH COM+

request and process it. The key thing to understand about SOAP is that it compliments my dis-
cussion on transports and payloads. It doesn’t replace it.
Data Services
142
PART II

Updating Records
Regardless of the transport mechanism you use, you still have to find a way to update the data-
base to reflect changes made by the user. Updating the database in a multi-user environment
can be problematic because releasing the database connection means that the records aren’t
locked. Therefore, another user can easily get the same records, edit them, and attempt to
update the database at the same time you do. When two people attempt to update the same
record simultaneously, it creates a collision.
At this point, you need to stop and answer some questions about the application you are build-
ing. Although it’s true that a possibility exists of overwriting changes made by other users, you
have to decide what the probability is that two users will attempt to edit the same data at the
same moment. The answer to this question affects how you deal with collisions.
Imagine that you are building an application that allows project managers to see and edit infor-
mation about scheduling and milestones in ongoing projects. In this case, assume that each
project manager is in charge of a unique project and that no two managers make entries for the
same schedule. In this case, it’s clear that there’s little or no possibility of one project manager
interfering with another.
Contrast the previous application with an order fulfillment system used to process orders and
send customer invoices. In this case, several people are working on the system. Anyone on the
system can update balances, print invoices, and update product inventory, which means that we
have a much higher possibility of problems. The amount of work you have to do to success-
fully implement this system is much higher than the first example.
When you use firehose cursors, updates are normally performed by building SQL UPDATE,
DELETE, or INSERT statements to directly manipulate the database. Users receive data in the
form of a string, array, or object. They edit the data in this format and then submit their
changes. The changes are used to generate SQL statements that are fired directly against the
database. Because there’s no direct handling of collisions, it can be easy to overwrite data.
Disconnected recordsets, on the other hand, are updated by reconnecting them to their original
database. Reconnecting a recordset is simply a matter of establishing a new connection and
setting the ActiveConnection property of the recordset. The database then attempts to imprint
the changes onto the database. User changes are sent back to the database as a batch using the
UpdateBatch method. The UpdateBatch method will fail if any of the attempted changes con-
flict with changes made by a previous user. The code in Listing 5.9 shows how a COM+ com-
ponent might receive a recordset as an argument and perform an update on the database.
Accessing Data with COM+
143
CHAPTER 5

LISTING 5.9 Performing a Batch Update


Public Function Update _
(ByVal objRecordset As ADODB.Recordset) As Boolean

Update = True

On Error GoTo UpdateErr

‘Reconnect and attempt update


objRecordset.MarshalOptions = adMarshalModifiedOnly
objRecordset.ActiveConnection = _
“Provider=SQLOLEDB;Data Source=(local);Database=pubs;UID=sa;PWD=;”
objRecordset.UpdateBatch

Exit Function

UpdateErr:
Update = False
Exit Function

End Function

When you use disconnected recordsets, it’s important to understand how ADO goes about
making an update. Disconnected recordsets determine what data to update by comparing cur-
rent values in the database with the data that was originally retrieved from the database. This is
possible because the disconnected recordset keeps a copy of the original data as well as the
changes you make. That’s right, it keeps two copies of the recordset for comparison. You can
access the current value of a record by using the Value property. If you want to see the original
value, you can access it through the OriginalValue property. The actual value in the database
is read through the UnderlyingValue property. When a disconnected recordset is reconnected
with the original database, it sends changed records back to the database based on differences
between the Value and OriginalValue properties.

Handling Collisions
Before beginning to write any application logic to deal with update collisions, you must first
determine what collisions are possible in your application and how much you care about them.
Collisions occur in only a few well-defined cases. First, a collision can occur if you attempt to 5
update a field in a record that someone else has already updated. In this case, the
ACCESSING DATA
WITH COM+

OriginalValue isn’t the same as the UnderlyingValue.


Data Services
144
PART II

You might also get a collision if other fields in the record were updated. In this case, fields you
have changed weren’t updated, but unrelated fields in the same record were. This can cause an
update to fail.
Deleted records can cause several types of collisions. You might, for example, attempt to edit a
field, but the underlying record was deleted. You might try to delete a record that someone else
has modified. Finally, you might try to delete a record that was previously deleted.
All these collisions are possible because scaleable applications don’t have the same concur-
rency controls as cursor applications. However, most of these collisions aren’t critical in a run-
of-the-mill business application. In many cases, simply refreshing a client’s data might be
sufficient to overcome the problem. In any case, you must determine how critical these colli-
sions are to your particular application.
You can control several aspects of collisions through the use of the Update Criteria property.
Update Criteria isn’t a property that you can access directly from a Recordset object. Instead,
it’s a member of the Properties collection. The Update Criteria property must be set before
you open the recordset. The property is read-only after you run a query. You can set this value
to one of four possibilities: adCriteriaKey, adCriteriaAllCols, adCriteriaUpdCols, and
adCriteriaTimeStamp. The following code shows how to set the property:

Dim objRecordset As ADODB.Recordset


Set objRecordset = New ADODB.Recordset
objRecordset.Properties(“Update Criteria”)=adCriteriaKey

The default value for Update Criteria is adCriteriaUpdCols. This setting determines conflict-
ing updates based on only the changed fields in your recordset. In this case, the current value
in the database (called the UnderlyingValue) is compared to the OriginalValue. If these val-
ues are different, the database assumes that a problem exists and fails the update.
Setting Update Criteria to adCriteriaKey uses the primary keys found in your query to update
the database whether or not someone else has made changes. The adCriteriaAllCols option
causes all the fields in the record to be examined for collisions, and the update fails if the
UnderlyingValue differs from the OriginalValue in any case. Finally, you can use a time-
stamp field with the adCriteriaTimeStamp option. Therefore, a collision is generated when the
update criteria isn’t met.
Although many programmers seem very concerned with collisions, in most business applica-
tions, they are relatively harmless. In fact, most applications can simply use the adCriteriaKey
setting for the Update Criteria. This means that every change made by every user is simply
written to the database without checking for many varieties of collisions. You might have users
overwriting each other’s data with reckless abandon. So what? Does it really matter to your
application if users overwrite each other? In most cases, probably not. But if this is critical to
your application, you will have to engage in more complex collision resolution.
Accessing Data with COM+
145
CHAPTER 5

EXERCISE 5.1

Creating a Data Layer


The first step in understanding distributed applications is learning to contain data access func-
tions within a separate layer. To create the data layer, you can use any of the transport schemes
discussed in this chapter. In this exercise, I use the ADO Stream object to return an XML
string to an Active Server Page. The XML is formatted into HTML through the use of an XSL
style sheet.
Building the Data Class
Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
05\Exercise 5.1. This directory contains some partially completed project files.

Step 2
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
5.1. Copy the contents from the CD-ROM directory into this new directory.

Step 3
Open the file transport.vbp in Visual Basic. This DLL contains one class, Books. This class
accesses the pubs database to return book information based on a partial title name passed in
as an argument.

Step 4
Examine the GetData method. You will see that the method uses a firehose cursor to return
records. The records are transformed into an XML string using the Stream object. The result-
ing XML is then returned from the function. The code in Listing 5.10 shows the function.

LISTING 5.10 The GetData Method


Public Function GetData(ByVal strTitle As String) As String

‘This function returns


‘book titles in XML format
5
On Error GoTo GetDataErr
ACCESSING DATA
WITH COM+

‘Get Records
Dim m_Recordset As ADODB.Recordset
Data Services
146
PART II

LISTING 5.10 Continued


Dim strSQL As String

Set m_Recordset = New ADODB.Recordset

strSQL = “SELECT * FROM titleview “


strSQL = strSQL & “WHERE Title LIKE ‘%” & strTitle & “%’”

m_Recordset.ActiveConnection = _
“Provider=SQLOLEDB;Data Source=(local);Initial Catalog=pubs;UID=sa;PWD=;”

m_Recordset.Source = strSQL
m_Recordset.Open

‘Persist in Stream
Dim m_Stream As ADODB.Stream
Set m_Stream = New ADODB.Stream

m_Recordset.Save m_Stream, adPersistXML

‘Return XML Stream


GetData = m_Stream.ReadText

GetDataExit:
Exit Function

GetDataErr:
Debug.Print Err.Description
App.StartLogging App.Path & “\error.log”, vbLogToFile
App.LogEvent Err.Description, vbLogEventTypeError
Resume GetDataExit

End Function

NOTE
The code for the function assumes that SQL Server is installed locally and that access
is performed as system administrator. If your installation is different, you might have
to change this code.

Step 5
Compile the DLL and close Visual Basic.
Accessing Data with COM+
147
CHAPTER 5

Step 6
With the Component Services explorer, create a new COM+ application named Stream. Add
the compiled DLL as a new component to the application.

Step 7
In the Component Services explorer, expand the treeview to locate the GetData method. Open
the property sheet for this method and enable the Auto Done feature.

Building the Web Site


Step 8
Create a new Web project using Visual InterDev. Name this new project WebStream.

Step 9
Locate the files search.htm, results.asp, and results.xsl. Add these files to the new Web
project.

Step 10
Open the file results.asp in Visual InterDev. This page uses search information entered in
search.htm to request data from the Transport component. The resulting XML is simply writ-
ten directly into the page. Notice how few lines of code are required within the ASP page. This
is one significant advantage of containing the data access code within a data class. The follow-
ing is the code from the ASP page:
<%@ Language=VBScript %>
<?xml version=”1.0”?>
<?xml:stylesheet type=”text/xsl” href=”results.xsl”?>
<%
Set objData = Server.CreateObject(“Transport.Books”)
Response.Write objData.GetData(Request.Form(“txtTitle”))
%>

Step 11
Open the style sheet results.xsl. This style sheet transforms the XML into an HTML table.
In fact, this style sheet is generic enough to be used to transform any set of records into a
table. It reads the <SCHEMA> section of the XML to create the column headers and the <DATA>
section to create the rows. Figure 5.13 shows the final output from the project.
5
ACCESSING DATA
WITH COM+
Data Services
148
PART II

FIGURE 5.13
The records are formatted as HTML.
COM+ Data Components CHAPTER

6
IN THIS CHAPTER
• Encapsulating Stored Procedures 151

• Parameter Passing 154

• Error Handling 161

• Polymorphic Interfaces 163

• The DNA Payload 167

• Conclusion 175
Data Services
150
PART II

As long as I have been teaching Windows DNA architecture, no topic gets more discussion
than data components. This is probably because data components are the most familiar to
developers. The code written in data components uses ADO to access a database—something
everyone has done. However, data access in a distributed application varies greatly from typical
two-tier corporate solutions. In this chapter, I will present a framework for building successful
data components along with alternative solutions. The objective of my discussion is to clearly
present the strengths and weaknesses of various approaches to constructing a data services
layer.
Before I begin a detailed discussion about designing and building data components, let’s agree
on a simple statement of fact: The function of a data component is to read and write data to a
data source. Although this statement might seem simplistic and obvious, its meaning comes
from what it does not say. Data components don’t, for example, initiate or control transactions.
They might participate in a transaction, but they are never the final arbiter of success or failure.
Data components also don’t make business decisions. Mechanisms such as triggers—which
update tables based on conditional statements—are out of place in the data services layer. Data
components are ignorant slave classes that simply read and write when directed. One of the
most common architectural errors in Windows DNA applications is the overloading of data ser-
vices with inappropriate functionality.

Key Principle
Data components perform no other function except to read and write data when
called.

Once we agree on the function of a data component, it becomes easier to understand how to
design one. The goal of our design is to create a “black box” into which we send parameters
and out of which we receive data. The data component is said to encapsulate the data access
operation, effectively hiding the details of the operation from a calling client. This encapsula-
tion removes dependencies between components and makes maintenance significantly easier.
Although most developers will agree with this discussion, I find that strong disagreements
might arise as I try to implement the architecture to encapsulate data access. In an effort to sort
out the strengths and weaknesses of various approaches, I present my preferred data compo-
nent design first. Then I will address common concerns with this design. Before proceeding,
however, I should note that no data component design is without limitations. I never discuss
any aspect of architectural design in terms of “right” and “wrong.” Instead, you should be
keenly aware of the pros and cons for every design so that you can make appropriate choices
when necessary.
COM+ Data Components
151
CHAPTER 6

Encapsulating Stored Procedures 6


The data services layer consists of a set of components that encapsulate Structured Query

COM+ DATA
COMPONENTS
Language (SQL) statements, accept input parameters in a standardized format, and output data
in a standardized format. In my design, I prefer to use Transact-SQL statements in the form of
stored procedures operating against a SQL Server database. Stored procedures are superior to
standard SQL statements because they are contained within the database and referenced by
name. In fact, a stored procedure represents the first level of encapsulation in our design. This
is because the body of a stored procedure can often be changed without changing the code in
the data component itself. One goal of our design is to allow the greatest amount of system
maintenance to be performed without recompiling any component.
Although stored procedures offer an excellent level of encapsulation, we must never allow
business or user services to directly access these stored procedures. Accessing a stored proce-
dure directly requires intimate knowledge of the database itself. Components that call stored
procedures will need, for example, a connection string containing information such as the data-
base name or server location. This type of knowledge must be restricted to the data services
layer only. If components outside data services are relying on intimate knowledge of the data-
base, changes to the database name or location will cause maintenance issues throughout the
system.
Our design seeks to further the level of encapsulation by containing each stored procedure
within its own data component. Our data services layer consists of many data components,
each capable of executing only a single stored procedure. Furthermore, we typically name the
class module to indicate the view of the data it returns or the write operation it performs.
Suppose that we wanted to return all the author information from the pubs database. We might
create a stored procedure named sp_GetAllAuthors and encapsulate it in a class named
CGetAllAuthors. Figure 6.1 shows a conceptual drawing of this approach.

CGetAllAuthors

Parameters In
sp_GetAllAuthors
Authors
Date out Table

FIGURE 6.1
A stored procedure encapsulated in a class module.

By following this approach, we typically design a full set of stored procedures to read and
write to each table. We also create stored procedures to generate all the views we might need to
present data to the user. This results in a large number of small class modules that are nearly
Data Services
152
PART II

identical except for the stored procedure they execute. Upstream components in the business
services layer can then use these components to retrieve views of the data or perform updates.
As you’ll see in Chapter 7, “COM+ Transactions,” this design also facilitates transactional
management by allowing the business services layer to enlist multiple data components in a
single transaction. Figure 6.2 shows a conceptual drawing of the relationship between business
services and data services.

Business
Component Data
Component stored procedure
Data
Component
Data stored procedure

Business Component stored procedure


Data
Component Component stored procedure
Data
Component stored procedure
Data
Component stored procedure
Business Data
Component Component stored procedure

Business Services Data Services Layer


Layer

FIGURE 6.2
Many data components are accessed by the business services layer.

One hallmark of our design is that each data component is identical except for the name of the
stored procedure being called. This means that we will have to deal with a significant amount
of repeated code. When you use ADO to access stored procedures, the following code would
be typical for the internals of a data component:
Set objRecordset = New ADODB.Recordset
objRecordset.Open _
“EXEC sp_GetAllAuthors” _
m_Connect, adOpenStatic

On seeing this level of repeated code, many developers exhibit shock and horror. There’s some-
thing fundamentally abhorrent to developers about repeating code, and in most cases this is a
good instinct. In this case, I believe it’s misguided, so I will address the alternatives.
The primary alternative to creating many small (also called fine grain) components with
repeated code is to create one large (also called coarse) component that performs all the data
access. I have seen this solution many times and it involves creating a single component that
accepts as an input the name of the stored procedure to run. In this way, no data access code is
repeated and the solution is simplified. Figure 6.3 shows a conceptual drawing of this com-
monly used alternative architecture.
COM+ Data Components
153
CHAPTER 6

Parameters and
stored procedure
6
name as input One large component

COM+ DATA
COMPONENTS
performing all data
Dataout access

FIGURE 6.3
Developers often avoid repeated code by creating one coarse data component.

Using a single coarse component has several disadvantages. First, when you use a single
coarse component, you must provide the name of the stored procedure as an input. This strat-
egy creates a dependency between the upstream business services layer and the database itself.
This means that any changes to the names of the stored procedures will require changes to the
components in the business services layer. This can cause a significant maintenance problem.
I have sometimes seen this issue addressed by using an enumerated value to specify the query
to run. Rather than pass the name of the stored procedure, a calling component simply passes a
long integer corresponding to a stored procedure in the database. This strategy is better, but
does require some work to coordinate the enumerated values and the stored procedure names.
In addition to maintenance problems, a single coarse component can also cause serious perfor-
mance problems. This is because you can easily set up a situation in which all data access calls
are made across a process boundary. Remember that each COM+ application you define in the
Component Services Explorer represents a separate running instance of dllhost.exe.
Therefore, if you place your single data access component in a separate COM+ application
from the components that call it, every call will be a cross-process call—the slowest call you
can make.
Deploying the data component in the same COM+ application as the business components
solves the cross-process issue. However, this means that every COM+ component in your sys-
tem must reside in the same application. This is a dangerous requirement because an adminis-
trator can easily create new COM+ applications and move components. The point is that your
system might experience significant performance degradation through simple ignorance on the
part of the administrator. All in all, I haven’t seen many successful implementations of coarse
data access components.

Key Principle
Use many fine-grain components to create a data services layer.
Data Services
154
PART II

This brings me back to my preferred design. Certainly, my architecture has the disadvantage of
repeated code in many components. To transition many fine-grain components between differ-
ent versions of ADO could possibly require a significant amount of work, but my solution suf-
fers from none of the dependency or performance issues outlined previously. When trying to
decide exactly how to design your system, the most important point is to understand the
strengths and weaknesses of each approach. I have seen too many systems fail simply because
developers were “making it up as they went along.”

Parameter Passing
After you decide to encapsulate your data access queries within components, you need to
decide on a standardized methodology for sending query parameters into the component. In
Chapter 5, “Accessing Data with COM+,” we examined different techniques for sending data
out of the component, and this discussion is similar. In many ways, it doesn’t matter whether a
package of data is going into the component or coming out—the issues are largely the same. In
the following sections, we examine the various strategies for sending parameters to a data com-
ponent.

Strong Function Signatures


The most common technique for sending data into a component is to use a strong function sig-
nature. This technique uses a standard method structure in a class module to define the parame-
ters required. The following code, for example, might be used to request all books in the pubs
database written by a certain author and containing a certain keyword:
Public Function GetBooks _
(ByVal strAuthor As String, _
ByVal strKeyword As String) As Recordset

This function signature requires two strings as inputs and returns an ADO Recordset containing
the data. The advantage of this approach is that the strong typing of the arguments helps to
ensure that the proper data is sent to the component. We also get the added benefit of
Intellisense within the Visual Basic environment. Intellisense will display the function signa-
ture as the call is coded, which also helps ensure accuracy. Figure 6.4 shows the Intellisense
feature in Visual Basic.
The drawback with the use of strong function signatures is that they don’t promote a standard
way of dealing with input parameters. Each call to a data component is a unique operation
requiring that the calling component specially tailor the input data to meet the function signa-
ture. In the same way that we want to standardize the format of the data leaving the compo-
nent, we want to standardize the format of the arguments sent into a component. In fact, we
can use all the same transport mechanisms discussed in Chapter 5 to send parameters into the
component.
COM+ Data Components
155
CHAPTER 6

COM+ DATA
COMPONENTS
FIGURE 6.4
Intellisense enhances strong function signatures.

Variant Arrays
Although we can use any transport to send data into the component, Variant arrays are good
to discuss because they represent a transport that isn’t self-defined. In the same way that we
used Variant arrays to return data, we can create a Variant array to send data into the compo-
nent. Creating this array is fairly simple and requires us to use only the Visual Basic Array()
function.
Utilizing a transport instead of a strong function signature requires us to change the way we
define methods in our data components. Now instead of individual arguments, we simply
define one argument to receive the transport. The following code shows how the strong func-
tion signature of the previous section would appear if we used a Variant array instead:
Public Function GetBooks _
(Optional ByVal vArgs As Variant) As Recordset

Notice that all the arguments are replaced by the single Variant. Notice also that we’ve
included the Optional keyword in the function signature. This means that we can pass in zero
to an unlimited number of arguments. This approach gives us a significant amount of flexibil-
ity and further reduces the dependencies between the business and data services layers. This
type of function signature also leads to a significant degree of standardization. You will see
later that we can use this standardization to define a set of interfaces that will further enhance
the modularization of our system.
The disadvantages to this approach are also noteworthy:
• We will lose any assistance we might have gained from Intellisense.
• All type checking is eliminated, which means that the compiler won’t be able to spot
type mismatches at compile time. Because all the arguments are contained within the
array, inappropriate arguments might be passed into the component. For example, the
array could easily contain an object reference. This would assuredly cause an error
within the data component that would never be caught until runtime.
Data Services
156
PART II

Calling components must package their data correctly to use the Variant array. This means that
the data types and the order of the arguments are critical. In our case, we expect the author’s
name to be first followed by the keyword. If, for example, we wanted to search for books by
“Hillier” about “COM+”, we would prepare our arguments as follows:
Dim MyArgs As Variant
MyArgs = Array(“Hillier”,”COM+”)

Furthermore, the data component would expect the arguments in this order. Because the
Variant array isn’t self-defined, the data component has no way of discovering the order of the
arguments at runtime. Instead, we usually rely on an enumeration to define the schema of the
payload. This enumeration might appear as follows:
Public Enum QueryArgsEnum
Author
Keyword
End Enum

Once the schema is defined in the enumeration, it can be used by the data component to run
the query. This makes the code readable, but doesn’t guarantee the order or accuracy of the
data passed in. To help guarantee the order and accuracy, we use the Assert method of the
Visual Basic Debug object. Debug.Assert() is a method built into Visual Basic that allows you
to test the validity of data within a component. The Assert method takes as an argument a
statement that should be True if the system is functioning correctly. If the statement is True,
nothing happens. If the statement evaluates to False, Visual Basic will enter debug mode.
Therefore, we could add the following code at the top of the data component function to test
the incoming arguments:
Debug.Assert VarType(vArgs(Author)) = vbString
Debug.Assert VarType(vArgs(Keyword)) = vbString

The assertion statements test to ensure that two arguments are passed through the array and
that they are both strings. Assertions are an excellent way to catch errors, but they also have
limitations. Assertions work only when you run your application in Visual Basic. After the
component is compiled, the assertions are meaningless. Furthermore, complicated assertions
can lead to significant “assertion maintenance.” This occurs when you change the format of the
arguments and the assertions keep breaking because you haven’t updated them. Figure 6.5
shows a typical assertion break in Visual Basic.
The conclusion we reach regarding Variant arrays is that they’re useful, but have some draw-
backs that make them less attractive. What we need is a transport that overcomes some of these
limitations while preserving the advantages of a standardized interface. Again, we will turn to
XML for the solution.
COM+ Data Components
157
CHAPTER 6

COM+ DATA
COMPONENTS
FIGURE 6.5
Assertions help ensure appropriate arguments are passed.

QUICK CHECK 6.1

Parameters in Variant Arrays


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 06\Quick Check 6-1. This directory contains a project you can use
to pass parameters in a Variant array.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 6-1. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Open the project named arrayargs.vbp in Visual Basic. This DLL contains a method
that accepts a Variant array as an input and returns a recordset as an output.
4. Open the class module named Query and examine the function signature for the
GetTitles method. This method is designed to accept two search criteria within the
Variant array. You can determine the required arguments and order by examining the enu-
meration found at the top of the class. Note also the assertion statement located in the
body of the procedure.

NOTE
The connection string in this example assumes that SQL Server is running locally and
is set up for standard security. If your installation is different, you might have to mod-
ify this code.
Data Services
158
PART II

5. Compile the DLL project and close Visual Basic.


6. Create a new COM+ application in the Component Services explorer named Array
Parameters. Install the compiled component into the new COM+ application.
7. Expand the tree view and locate the GetTitles method in the explorer. Open the prop-
erty sheet for the method and enable the Auto Done property.
8. Locate the file client.hta. This file calls the COM+ component and returns book infor-
mation based on a title and author search criteria. Double-click this file to start the appli-
cation. Figure 6.6 shows the page.

FIGURE 6.6
Use this page to pass search criteria and return records.

9. Use the HTA page to enter author and title information. Then click the button to return
records. This page packages your search parameters into a Variant array and then passes
them to the data component. The resulting ADO recordset is then bound to a DHTML
table for display.

XML
Using XML to pass parameters into a data component has many of the same advantages that
made them attractive for returning data. XML is a form of delimited string, so it’s fast, and
XML supports a self-defined payload in the form of a schema section. For these reasons, XML
COM+ Data Components
159
CHAPTER 6

is superior to a Variant array; however, using an XML transport will still eliminate the type 6
checking of strong function signatures. The following code shows how an XML function sig-

COM+ DATA
COMPONENTS
nature would appear:
Public Function GetBooks _
(ByVal strArgs As String) As Recordset

In this case, we simply change the input data type from a Variant to a String. The String variable
will hold all the arguments as an XML payload. To use the arguments, we must open the pay-
load. In this case, however, we could use the schema section of the XML to ensure that we’ve
received the expected arguments and data types. These checks could then be incorporated into
assertions without the requirement to have the schema defined in a separate enumeration.
When it comes to examining the payload delivered by the XML transport, we might choose to
directly examine the data through the use of the MSXML parser. In Chapter 5, you saw that
this parser is cumbersome and difficult to code accurately. When we used XML to transport
records back to clients, we solved the problem by converting the XML string to a Recordset
using the Stream object. This is exactly how we will handle sending arguments to a data com-
ponent.
Clients wanting to send search criteria into a data component don’t have a simple way to pack-
age the criteria as XML. In some solutions, programmers use the MSXML parser to create an
XML stream from the criteria, but any use of the parser entails difficult coding, so we choose
instead to create our XML stream from a standalone Recordset. The overall strategy is to cre-
ate a standalone Recordset, append the search criteria, convert it to XML, and pass it to the
data component. The data component then converts the XML back to a recordset to access the
search criteria.
Creating a standalone Recordset is accomplished by simply instantiating an ADO recordset
without connecting to a database. After the Recordset is created, you can add any fields you
want by using the Append method. This method defines the schema for the new recordset.
Finally, data can be placed in the Recordset using the AddNew method. The following code
shows how to create a Recordset with two fields:
Set objArgs = New ADODB.Recordset
objArgs.Fields.Append “Author”,adChar,50
objArgs.Fields.Append “Keyword”,adChar,50

objArgs.Open
objArgs.AddNew

objArgs!Keyword = “COM+”
objArgs!Author = “Hillier”

objArgs.Update
Data Services
160
PART II

After the recordset is created, you can use the standard methods discussed in Chapter 5 to cre-
ate the XML stream and pass it to the data component. After the recordset is re-created in the
data component, we can use the enhanced schema information to declare more sophisticated
assertions. The following code shows how to check the number of arguments passed in:
Debug.Assert objCriteria.Fields.Count = 2

QUICK CHECK 6.2

Parameters in XML Streams


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 06\Quick Check 6-2. This directory contains a project you can use
to pass parameters in XML streams.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 6-2. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Open the project named xmlargs.vbp in Visual Basic. This DLL contains a method that
accepts a String as an input and returns a Recordset as an output.
4. Open the class module named Query and examine the function signature for the
GetTitles method. This method is designed to accept two search criteria within the
XML String.

NOTE
The connection string in this example assumes that SQL Server is running locally and
is set up for standard security. If your installation is different, you might have to mod-
ify this code.

5. Compile the DLL project and close Visual Basic.


6. Create a new COM+ application in the Component Services explorer named XML
Parameters. Install the compiled component into the new COM+ application.
7. Expand the tree view and locate the GetTitles method in the explorer. Open the prop-
erty sheet for the method and enable the Auto Done property.
8. Locate the file client.hta. This file is used to call the COM+ component and return
book information based on a title and author search criteria. Double-click this file to start
the application. This page has the same user interface as Quick Check 6.1, but creates an
XML stream instead of a Variant array.
COM+ Data Components
161
CHAPTER 6

9. Use the HTA page to enter author and title information. Then click the button to return 6
records. This page packages your search parameters into an XML stream and then passes

COM+ DATA
COMPONENTS
them to the data component. The resulting ADO recordset is then bound to a DHTML
table for display.

Error Handling
Handling errors in your COM+ applications requires special consideration primarily because
of the problems caused by unhandled errors. In previous chapters, I showed that unhandled
errors prevent the proper deactivation of components within a COM+ application. In Chapter 7
we will see that they can also negatively impact transactional management. Therefore, we must
always trap errors within COM+ components and report these errors in a controlled and stan-
dardized way.
The problem with handling errors is that you can never seem to find a clean way to return error
codes to clients. In some designs, the return value of the function is reserved for error return val-
ues; however, this means that data must be returned through a By Reference argument, which is
a poor performance choice. What we really want is a way to pass both data and error informa-
tion as a single return value from a function. This is where the XML transport really shines.
XML data can be considered a hierarchical set of nodes. When a Recordset is converted to
XML through a Stream object, a set of schema nodes and a set of data nodes are created. The
structure of these nodes can be standardized, but through the use of the MSXML parser, we
can add additional nodes to the payload that contain error information. Once the error nodes
are appended to the payload, we can use the single String return value to send the schema,
data, and error information back to the client in a single operation. Figure 6.7 shows a flow-
chart of the process.
To append nodes to an XML stream, the stream must first be loaded into the MSXML parser.
This is done by creating an instance of the DOMDocument object and loading it by using the
LoadXML method. The following code shows how to convert a Recordset to XML and load it
into the DOMDocument:
Dim objStream As ADODB.Stream
Dim objRecordset As ADODB.Recordset
Dim m_XML As String

‘Run Query
Set objRecordset = New ADODB.Recordset
objRecordset.Open “SELECT * FROM Publishers”

‘Create XML Stream


Set objStream = New ADODB.Stream
Data Services
162
PART II

objRecordset.Save objStream, adPersistXML


m_XML = objStream.ReadText

‘Load DOMDocument
Dim objXMLStream As MSXML.DOMDocument
Set objXMLStream = New MSXML.DOMDocument
objXMLStream.LoadXML m_XML

Data Component is
called

Run Query

Convert Recordset
to XML Stream

Append Error
Errors? Yes
Nodes

No

Send XML to client

Data Received

FIGURE 6.7
Append error codes to XML Streams.

Once loaded into the DOMDocument, you can easily append nodes to the XML. Appending a
node is accomplished by first creating a new XML element. XML elements are created by
using the CreateElement method of the DOMDocument. A new XML element can then be
assigned a value and appended to the original document. The following code shows how to
append an error description to the XML stream created previously:
Dim objXMLElement As MSXML.IXMLDOMElement
Set objXMLElement = objXMLStream.createElement(“ErrDescription”)
objXMLElement.Text = Err.Description
objXMLStream.firstChild.appendChild objXMLElement
COM+ Data Components
163
CHAPTER 6

You can use this technique to append as many additional elements to the XML stream as you 6
need. You might, for example, want to append a time stamp to the data. You might also want to

COM+ DATA
COMPONENTS
include the entire contents of the ADO Errors collection. In any case, you have tremendous
flexibility to append system-defined information that can be easily transferred to the calling
component.
Keep in mind that when you modify the XML stream, it can’t be converted back into a
recordset until the additional nodes are removed from the XML. The ADO Stream object ex-
pects a certain format to properly convert the XML to a Recordset. Therefore, the client re-
ceiving the XML will have to use the MSXML parser to remove nodes appended by the data
component. The following code shows how to save the appended data and remove a node
from the XML:
Dim objXMLNode As MSXML.IXMLDOMNode

With objXMLStream.childNodes(0)
strDescription = .lastChild.Text
Set objXMLNode = .lastChild
.removeChild objXMLNode
End With

When error handling is entered into the mix, we begin to see the power of a data services strat-
egy relying on XML. We have built the case for a standard data component that accepts argu-
ments as an XML string and returns schema, data, and error information as an XML string. All
that remains is to enforce this standard through the use of polymorphic interfaces.

Polymorphic Interfaces
As you can see from the discussion thus far, the process of building and maintaining distrib-
uted applications is made easier through standard techniques and data packages. Standardizing
is accomplished when you use standard return values, standard arguments, and standard
method names. Standardizing function signatures in this way creates a clear boundary between
layers in the application and is at the heart of partitioning distributed tiers. Visual Basic pro-
vides a strong tool for guaranteeing the standardization of function signatures. This tool is
known as polymorphism.
In my opinion, polymorphism is the single best feature of Visual Basic and the most critical
technology in the construction of COM+ applications. Polymorphism is also the least under-
stood of all Visual Basic features. In my experience, precious few developers understand the
nature of polymorphism, and even fewer understand how to use it to guarantee success in
COM+ applications.
Data Services
164
PART II

NOTE
At this writing, Visual Basic 7.0 has been demonstrated as an early alpha product. At
these showings, you’ve seen that VB 7.0 will contain a number of advanced object-
oriented capabilities such as inheritance. I remain concerned about the introduction
of such an advanced version of Visual Basic. No doubt some developers will make the
most of the new features, but if my experience with polymorphism is any guide, many
will have difficulty properly implementing these capabilities in their applications.
Preparing for VB 7.0 means learning how to properly use polymorphism in VB 6.0.

Understanding Polymorphism
Polymorphism can accurately be defined as two different classes with methods by the same
name. As an example, consider two different components that reside in the data services layer.
One component has a class named QueryAuthors; another component has a class named
QueryPublishers. These classes are different because one class queries for information about
authors, whereas the other queries for information about publishers. To get the data from these
objects, however, a client always calls the GetData method. This can either be
QueryAuthors.GetData or QueryPublishers.GetData. In this way, we have defined a standard
method for retrieving data from the database named GetData. This method name is used
regardless of the type of data you want. This is polymorphism: two objects of different types
with a method by the same name.
When we build COM+ applications, we want to standardize the methods in the components to
the greatest extent possible. This helps developers know what to expect from a function as well
as what arguments to pass. Before Visual Basic had polymorphism, I used to recommend that
companies create a document that defined the standard function signatures that would be used
by developers when they created various types of components similar to data access compo-
nents. After the document was written, it could be used during code reviews to ensure that
developers followed the corporate standards. These standards then ensured a high level of
maintainability in the application.
The problem with documented corporate standards, however, is that they require enforcement
through code reviews. Someone has to look at the code, point out where the code deviates from
the standards, and then rework the code. This requires quite a commitment on the part of a pro-
ject team, and frankly, we see very few teams capable of getting off the “death march” long
enough to perform adequate code reviews. Although code reviews are still an essential part of
any project, Visual Basic makes the enforcement of standards considerably easier through the
use of polymorphism. Using Visual Basic’s polymorphism, we can define corporate standards
in code and then have the compiler perform our “code review” at compile time.
COM+ Data Components
165
CHAPTER 6

Creating Standards 6
Defining standard function signatures in Visual Basic is accomplished by creating abstract

COM+ DATA
COMPONENTS
classes, class modules that contain the definitions of function signatures but don’t have any
code within them. Assume that we wanted to define a standard function signature for any class
wanting to encapsulate a stored procedure. We might create a standard method such as Query
and then dictate that this method will always accept an XML String as an argument and then
return data as XML. The following code shows the standard signature:
Public Function Query(ByVal strArgs As String)As String
End Function

If we want to use this signature as a standard, it should be placed in a class module in a sepa-
rate ActiveX DLL. We also won’t place any code at all in this function. That’s right—this
function is simply left blank in its own ActiveX DLL project. This allows us to standardize the
function signature, creating what is known as an interface. Interfaces are definitions of func-
tion signatures that can be used for standardization. Whenever you create an abstract class as
an interface, you should prefix the name of the class with a capital I. Thus, we could create a
class named IGetData with the function Query defined inside.
Once the interface is defined, it can be used to standardize any other class. This is accom-
plished by setting a reference in the project you want to standardize to the project that contains
the interface definition. After the reference is set, a new class module can use the interface by
declaring that the interface is implemented in the new class. This is done with the following
code:
Implements IGetData

When a class declares that it implements a polymorphic interface, it’s signing a contract with
the Visual Basic compiler. This contract promises that the new class will contain every member
of the interface within the new class. Thus, if the interface defines a method Query with a
String in and a String out, the new class must in turn define the same method. Failing to define
the new method will prevent Visual Basic from compiling the new class. In this way, the com-
piler acts as the standards enforcer for the project. It simply won’t allow the new class to com-
pile if the interface isn’t properly implemented.
Fortunately, Visual Basic helps us implement the required methods of an interface. If a class
declares that it implements an interface, Visual Basic will place the name of the interface in the
object box of the code window. When you select the object in the code window, Visual Basic
lists all the members of the interface in the procedure box of the code window. Figure 6.8
shows the code window when a class implements our IGetData interface.
Data Services
166
PART II

FIGURE 6.8
Visual Basic lists implemented interfaces in the code window.

When you build a class that implements an interface, you must use the code window to add
each member of the interface to your new class. Then you can write code in the new proce-
dures to define what happens when the method is called. Notice that when Visual Basic adds
an interface member to your class, it’s defined as a private procedure. For example, the follow-
ing code shows the implementation of the IGetData interface:
Private Function IGetData_Query(ByVal strArgs As String) As String

End Function

The members of the interface are Private in the implementing class because the Public part
of the interface is maintained by the abstract class built earlier. This is what standardizes the
function signatures. The abstract class acts as the public gateway for each and every class that
implements the interface. All you have to do is write the code for the functionality. This can
be identical to the code that you would write if you didn’t implement any interfaces in the
component.
Clients who want to call the Query method through the standardized interface can do so by
declaring a variable and creating a new instance. However, we don’t write this code in the
usual way. Instead, we declare an object variable as the interface, but create an instance of the
desired object. Suppose that the implementation code is in a class named QueryPublishers.
The following code creates an instance of this object for use by a client:
Dim objDataObject As IGetData
Set objDataObject = New QueryPublishers

Notice how this code declares the variable not as the name of the desired object, but as the
name of the interface. This is critical in defining the communication points between the two
objects in the COM+ application. Because the code in the client refers to the standard inter-
face, you can easily modify the manner in which the interface is implemented in the
QueryPublishers class without affecting the code in any other component that calls
QueryPublishers. Also, the interface has served to standardize the members of all data access
classes that encapsulate stored procedures. This makes development and maintenance consider-
ably easier than it would be if each developer defined his own custom method calls for encap-
sulating stored procedures.
COM+ Data Components
167
CHAPTER 6

6
Key Principle

COM+ DATA
COMPONENTS
Use interfaces to define the communications points between components in an
COM+ application.

Because interfaces define the standards for components in a COM+ application, they should be
used widely throughout the entire application. Anywhere a component engages in standard
behavior such as encapsulating stored procedures, returning XML, or maintaining application
state, interfaces should be used to define the function signatures. This also means that the inter-
faces must be defined before the implementing classes are coded. In fact, the interfaces should
be one of the first parts of an application that you create. Because interfaces are no more than
function signatures without code, you can create them by simply agreeing among the key appli-
cation architects on method names and argument types. Thus, it’s appropriate to create the
interfaces for an application shortly after the architects have modeled the application.

The DNA Payload


If we review and summarize our thoughts regarding passing arguments, data, and errors, we
find that several architectural characteristics are common throughout a COM+ system:
• We want to transfer data between any two tiers as a String.
• We want to operate on data within a tier as a Recordset.
• We want the ability to pass errors and system information.
• We want it all accomplished in a standard way.
To achieve these goals, we could write exhaustive transformation code in every layer of our
application; however, we will quickly find that we are writing exactly the same code in every
object we create. In fact, we would find that, unlike the data access code with ADO, there’s
absolutely no difference between the transformation code for any component in our system.
Therefore, data transformation from Recordsets to XML, management of system information,
and even some HTML, can be separated from the system and implemented in a single common
component. We call this component the DNA Payload object.
The DNA Payload object performs data transformation services for any component in our sys-
tem. Although we can enhance our payload objects to perform many related services, the fun-
damental service is transformation between XML and Recordset forms. When we create a
DNA Payload object, we intend to have every component communicate with it; therefore, it
won’t be placed under Component Services. Putting a utility component like this in a COM+
Data Services
168
PART II

application causes all calls to it to be across processes. This is the same reason that we can’t
create a common data access component. However, because the DNA Payload won’t have
transactional attributes, it can be designed as an unconfigured component. Unconfigured com-
ponents always load into the memory space of the calling client, so performance will be excel-
lent. Figure 6.9 shows a conceptual drawing of the DNA Payload object in a Windows DNA
application.

1. Search parameters are


converted to XML and passed to
the data component.
DNA Payload
Convert Recordset to XML

Convert XML to Recordset

Business Component Data Component


Component Interface
Search
Parameters
Execute Stored
Procedure

3. The process is repeated


to send the results of the
stored procedure back to
2. Search parameters are the calling client.
converted back to a
Recordset for use in the
stored procedure.

FIGURE 6.9
A DNA Payload object transforms data for any component.

DNA Payload objects might take many forms, and the thought process on this architecture is
still evolving. However, I’ve created a DNA Payload object for the final project in this book
and present it here to help you understand the fundamental concepts behind it. You will find
my version of this component on the CD-ROM in the TOOLS directory.

NOTE
The DNA Payload object included with this book is suitable for study and experimen-
tation only. Although the component has performed well under load, it isn’t
intended to be used on production applications without further testing and modifica-
tion. See Chapter 14, “Debugging and Deploying COM+ Applications,” for a complete
discussion of performance testing.
COM+ Data Components
169
CHAPTER 6

Overview 6
My DNA Payload consists of two class modules forming a simple object model. The top-level

COM+ DATA
COMPONENTS
object in the model is the Dataset object, which is responsible for performing the data transfor-
mation operations. It also contains a collection of Field objects that can be used to pass argu-
ments into components. Figure 6.10 shows the object model.

Dataset

Fields

Field

FIGURE 6.10
The DNA Payload has a Dataset object and Fields collection.

Dataset Properties and Methods


The Dataset object consists of properties to hold all the different representations of the data.
These include the fundamental ADORecordset and XML properties, but I have also incorporated
XSL and HTML properties to easily transform the data into browser-independent HTML. Table
6.1 lists the properties of the Dataset object.

TABLE 6.1 Dataset Properties


Property Description
ADORecordset The data in Recordset form
Count The number of Field objects in the collection
ErrDescription A description of a system defined error
ErrNumber A system defined error number
HTML The data in HTML form
Stream The data, schema, and error in XML form
XML The data in XML form
XSL The style sheet used to create the HTML

The Dataset object also contains individual methods for converting data between forms. This
makes the object flexible enough to convert between any form when you need it. Table 6.2 lists
the methods of the Dataset object.
Data Services
170
PART II

TABLE 6.2 Dataset Methods


Method Description
Add Adds a Field object to the Fields collection
Collection2Recordset Creates a recordset from the Fields collection
CreateStream Creates an XML stream with data, schema, and system infor-
mation
LoadXML Loads XML from a file
LoadXSL Loads XSL from a file
ParseStream Parses an XML stream containing data, schema, and system
information
Recordset2Collection Converts a recordset into a collection of Field objects
Recordset2XML Converts a Recordset into XML
Remove Removes a Field object from the collection
XML2HTML Transforms XML into HTML using the XSL style sheet
XML2Recordset Converts XML into a Recordset

Field Object Properties


The Fields collection exists primarily as a simple mechanism to pass parameters. The DNA
Payload object uses the Fields collection as the basis for creating a standalone Recordset. Once
the Recordset is created, it can be transformed into any required form. Table 6.3 lists the prop-
erties of the Field object.

TABLE 6.3 Field Object Properties


Property Description
FieldName A String name for the Field object
FieldSize The size of the field as a Long Integer
FieldType The field type as an ADO DataTypeEnum
FieldValue A Variant containing the value of the field

Passing Parameters with the DNA Payload


One of the first operations you will perform with the DNA Payload is passing parameters from
a client component to a data component. This process requires the client component to create
an instance of the DNA Payload object and add the parameters to the Fields collection. After
COM+ Data Components
171
CHAPTER 6

the Fields collection is populated, the collection can be converted to XML for delivery to the 6
data component. Figure 6.11 shows a flowchart outlining the process.

COM+ DATA
COMPONENTS
Start

Data Component
Create a DNA
creates a new DNA
Payload object
Payload object

Add Parameters to Load XML into DNA


the Fields Collection Payload object

Create XML from Create Collection of


Fields Collection Fields from XML

Run query using Field


Send XML Stream to
objects as parameters
Data component
for stored procedure

End

FIGURE 6.11
The Fields collection is used to pass parameters.

Using the Fields collection to pass parameters begins when a business component creates an
instance of the Dataset object. When initially created, the DNA Payload contains no data. It’s
an empty shell that must be filled with the data to pass. In this case, the business component
can use the Add method of the Fields collection available through the Dataset object. The fol-
lowing code shows how parameters might be added to the Fields collection:
Dim objParams As DNAPayload.Dataset
Set objParams = New DNAPayload.Dataset
objParams.Add “Author”, adVarChar, “Hillier”, 50
objParams.Add “Keyword”, adVarChar, “COM+”, 50

Notice that the Fields collection follows the same conventions used to append new fields to a
standalone Recordset. This is because the DNA Payload automatically creates a standalone
Recordset each time the Add method of the collection is called. In this way, you can avoid the
tedious code required to create the standalone Recordset yourself. This is accomplished by
calling the Collection2Recordset method whenever a new Field object is added to the collec-
tion. The code in Listing 6.1 shows how the DNA Payload converts the Fields collection to a
standalone Recordset:
Data Services
172
PART II

LISTING 6.1 Converting the Collection to a Recordset


Dim objField As Field

‘Clear the underlying recordset


Set m_Recordset = New ADODB.Recordset

‘Create the fields


For Each objField In mCol
m_Recordset.Fields.Append _
objField.FieldName, _
objField.FieldType, _
objField.FieldSize
Next

‘Set the field values


m_Recordset.Open
m_Recordset.AddNew

For Each objField In mCol


m_Recordset.Fields(objField.FieldName).Value = _
objField.FieldValue
Next
m_Recordset.Update

Before data is sent to any component, it must be transformed to incorporate any system defined
information. The Dataset object has properties for both an error number and error description.
You don’t have to populate the values, but if you do, the DNA Payload can automatically
append the required nodes to the outgoing XML.
In the Dataset object, the Stream property contains the XML representation of the Recordset
and any appended system information. The Stream property is populated by the CreateStream
method. This method appends the ErrNumber and ErrDescription properties to the XML. The
value of the Stream property is then sent to the data component as a String. Listing 6.2 shows
the body of the CreateStream method.

LISTING 6.2 Creating the Output Stream


Dim objXMLStream As MSXML.DOMDocument
Dim objXMLElement As MSXML.IXMLDOMElement

‘Create Document
Set objXMLStream = New MSXML.DOMDocument
objXMLStream.LoadXML m_XML

‘Append Error Number


Set objXMLElement = _
COM+ Data Components
173
CHAPTER 6

objXMLStream.createElement(“ErrorNumber”) 6
objXMLElement.Text = m_ErrNumber
objXMLStream.firstChild.appendChild objXMLElement

COM+ DATA
COMPONENTS
‘Append Error Description
Set objXMLElement = objXMLStream.createElement(“ErrorDescription”)
objXMLElement.Text = m_ErrDescription
objXMLStream.firstChild.appendChild objXMLElement

‘Save Document Text


m_Stream = objXMLStream.XML

Returning Data with the DNA Payload


The Stream property represents the common currency exchanged between components. It
doesn’t matter whether you’re sending parameters into a data component or sending records
back to a business component. In both cases, the components expect to access the Stream
property to find the data. Data components begin the process of responding to a request by cre-
ating an instance of the Dataset object and setting the Stream property to the value sent in by
the calling component. To return records, the data component will need to create a new Dataset
object to hold the outbound data. Figure 6.12 shows a flowchart outlining the process.

Start

Data Component Data Component


creates a new DNA creates a new DNA
Payload object Payload object

Stream property is ADO Recordset and


loaded from passed error information are
in String added to DNA Payload

Stream is parsed to
populate Fields Outbound Stream is
collection and error created
information

Run query using Field Stream property is


objects as parameters returned to calling
for stored procedure client

End

FIGURE 6.12
The data component uses the DNA Payload to return records.
Data Services
174
PART II

Because the Stream property contains data, schema, and error information, it must be parsed
by the receiving client to access the Recordset generated as a result of running the stored pro-
cedure. Once parsed, the ADORecordset, ErrNumber, and ErrDescription properties can be
populated and accessed. The code in Listing 6.3 shows how the ParseStream method of the
Dataset extracts information from the returned Stream.

LISTING 6.3 Parsing the Returned Stream


Dim objXMLStream As MSXML.DOMDocument
Dim objXMLNode As MSXML.IXMLDOMNode

‘Load the Stream


Set objXMLStream = New MSXML.DOMDocument
objXMLStream.LoadXML m_Stream

With objXMLStream.childNodes(xmlRoot)

‘Get Description
m_ErrDescription = .lastChild.Text
Set objXMLNode = .lastChild
.removeChild objXMLNode

‘Get Number
m_ErrNumber = .lastChild.Text
Set objXMLNode = .lastChild
.removeChild objXMLNode

End With

‘Set XML property


m_XML = objXMLStream.XML
XML2Recordset
Recordset2Collection

Displaying HTML with the DNA Payload


Although the Stream is at the heart of the DNA Payload functionality, I found that I often
wanted to convert XML to HTML for the purpose of providing a browser-independent display.
Therefore, I built an HTML capability into the Dataset object.
The conversion from XML to HTML is accomplished by loading an XSL style sheet into the
XSL property of the Dataset object. This property can be loaded from either an XSL String or
by using the LoadXSL method to read the style sheet from a file. You will most likely use the
latter technique because your style sheets will probably be files located on a Web site.
COM+ Data Components
175
CHAPTER 6

After the XSL and XML properties are set, the XML2HTML method can be used to create an 6
HTML representation of the data. After the method is called, the resulting HTML is immedi-

COM+ DATA
COMPONENTS
ately available through the HTML property of the Dataset object. The following code shows
how the XML2HTML method creates the final HTML:
Dim objXMLDOM As MSXML.DOMDocument
Dim objXSLDOM As MSXML.DOMDocument

‘Load the XML and XSL documents


Set objXMLDOM = New MSXML.DOMDocument
Set objXSLDOM = New MSXML.DOMDocument

objXMLDOM.LoadXML m_Stream
objXSLDOM.LoadXML m_XSL

‘Transform the XML to HTML


m_HTML = objXMLDOM.transformNode(objXSLDOM)

Conclusion
Although developers can use many different architectures to create Windows DNA applica-
tions, I’ve arrived at my recommendations through careful examination of the goals for our
framework:
• We want the application to have a high-level of partitioning between tiers to improve
maintainability.
• We want excellent performance when transporting data between those tiers.
• We want a standardized approach that developers can master and use in every solution.
For these reasons, I’ve developed the recommendations presented in this chapter. Certainly,
research continues and generally accepted best practices will evolve, but for those seeking a
good foundation for their COM+ application, my framework is a good start.

EXERCISE 6.1

Investigating Payload Objects


The foundation of data transport is a good payload object. This exercise will allow you to
examine a simple payload object. You will use it to transform data between various formats
and display that information. As you work, consider what features you would want your pay-
load object to have.
Data Services
176
PART II

Building the Simple Payload Object


Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
06\Exercise 6-1. This directory contains some partially completed project files.

Step 2
On your hard drive, create a new directory with Windows Explorer named COM+\
Exercise 6-1. Copy the contents from the CD-ROM directory into this new directory.

Step 3
Open the project named xmlpayload.vbp. This ActiveX DLL project contains Dataset and
Field classes. This particular component is a derivation of my DNA Payload object that has
been simplified for this exercise.

Step 4
Open the Dataset class and examine its properties and methods. Much of the code in this class
is similar to the code discussed in the chapter.

Step 5
Locate the XML2Recordset method in the Dataset object. This method hasn’t been coded. Add
the following code in the location indicated to complete this method:
Dim objStream As ADODB.Stream

‘Create Recordset
Set objStream = New ADODB.Stream
objStream.Open
objStream.WriteText m_XML
objStream.Position = 0
Set m_Recordset = New ADODB.Recordset
m_Recordset.Open objStream

Step 6
Compile this DLL. There’s no need to put the DLL inside a COM+ application because this
component is intended to run as an unconfigured component. It will run in the memory space
of the calling client.
Running the Project
Step 7
Open the project named frontend.vbp, located in the \Front End directory. This project will
allow you to exercise the payload object.
COM+ Data Components
177
CHAPTER 6

Step 8 6
Run the front-end project.

COM+ DATA
COMPONENTS
Step 9
When the project starts, you will see a multiple document interface (MDI) form with a menu.
This form allows you to convert Recordsets, XML streams, HTML, and search parameters to
different forms. Figure 6.13 shows the MDI form.

FIGURE 6.13
Use this form to investigate the payload functionality.

Step 10
Begin by selecting Recordset from the Convert menu. When you make this selection, a form
will appear with a SQL statement. If you execute this SQL statement, the results of the state-
ment are returned as a Recordset and displayed in a databound grid. Figure 6.14 shows the data
displayed in the grid.

Step 11
With the Recordset data visible, click the Convert button to populate all the properties for the
payload and allow you to view various forms.

Step 12
Select XML from the View menu. This displays the Recordset converted to an XML stream.
Figure 6.15 shows the XML.
Data Services
178
PART II

FIGURE 6.14
Begin by creating a Recordset.

FIGURE 6.15
Convert the Recordset to XML.

Step 13
Select HTML from the View menu. The payload uses an XSL style sheet to create HTML and
display it in the browser. Figure 6.16 shows the resulting HTML table.

Step 14
Try various other combinations to test how the payload works. You might then want to go back
and examine the code more carefully to understand how it functions.
COM+ Data Components
179
CHAPTER 6

COM+ DATA
COMPONENTS
FIGURE 6.16
XSL is used to transform the XML to HTML.
COM+ Transactions CHAPTER

7
IN THIS CHAPTER
• Understanding Transaction Attributes 182

• The Microsoft Distributed Transaction


Coordinator 183

• Transactional Components 184

• Monitoring Transactions 198


Data Services
182
PART II

In the past, transactional control was coded directly into a system through function calls. In
fact, you can still use this capability in the ADO object model through the BeginTrans,
CommitTrans, and RollbackTrans methods. Although these ADO transaction methods will
work fine with a COM+ component, the problem is that the transaction control resides in the
code. If you want to change how the transaction is managed, you have to change the code. One
key feature provided by COM+ is the ability to initiate, monitor, and commit transactions on
databases that use declarative attributes set in the Component Services Explorer. The purpose
of these declarative transactional attributes is to eliminate the need to change transaction code.

Understanding Transaction Attributes


The classic example of a database transaction is the transfer of money between accounts at a
bank. Suppose that you want to transfer money from your savings account at one bank to a
checking account at another bank. From a database perspective, this operation requires two
independent actions. Funds must be removed from the savings account and then added to the
checking account. If either of the separate actions fail, money will be created or destroyed—a
significant problem for the banking system.
Transactions are designed to prevent the problems that arise when related database actions are
dependent on each other. When describing transactions, I talk about a set of attributes that
define a transaction and prevent catastrophic failures. The first attribute of a transaction is
atomicity, which simply states that all parts of a transaction must succeed or fail as a single
unit. In the case of the money transfer, if either the debit or the credit operation fails, both
actions must be negated. Negating the partial work of a transaction is called a rollback.
The second attribute of a transaction is consistency, which says that the transaction must take
the database from one stable state to another. No operations are left partially complete, and
completing a transaction makes the system ready to perform a new transaction. Consistency
requires that the system be able to handle any number of transactions in any order without neg-
ative impact on the overall system.
The third attribute of transactions is isolation, which requires each transaction to operate inde-
pendently from other transactions. All dependent operations are part of a single transaction. No
other transactions operating on the same system at the same time can negatively affect the cur-
rent transaction. Furthermore, other transactions can’t see the intermediate results of an execut-
ing transaction. Results are visible to the system only after the transaction succeeds or fails.
The final attribute of transactions is durability, which means that the results of a transaction are
permanent and can be undone only by a subsequent operation. This means that hardware fail-
ure must not affect the transaction’s results.
COM+ Transactions
183
CHAPTER 7

NOTE
These transaction attributes are said to be ACID attributes because of the first letter
for each key attribute (Atomicity, Consistency, Isolation, Durability). The ACID attrib-
utes form the heart of every transaction performed on a database.

When transactions are performed, they might be executed as several actions against a single
database or as a group of actions that spans many databases. When a transaction is performed
against multiple databases, it’s called a distributed transaction. Distributed transactions that
7
conform to the ACID requirements are said to engage in a two-phase commit. Two-phase com-

TRANSACTIONS
mit engages in communication between transaction and resource managers to ensure compli-

COM+
ance with the ACID principles. In COM+ applications, a two-phase commit is implemented by
the Microsoft Distributed Transaction Coordinator (MSDTC).

The Microsoft Distributed Transaction Coordinator


MSDTC runs as a service under Windows 2000. MSDTC is responsible for initiating, monitor-
ing, and committing distributed transactions that meet the ACID requirements. MSDTC can act
as both an initiator and a participant in a distributed transaction through the use of the two-
phase commit protocol.
Two-phase commit receives its name from the two distinct phases of a distributed transaction:
prepare and commit. When a distributed transaction takes place under two-phase commit, the
transaction is controlled through a series of commands and responses that form the two-phase
commit protocol. MSDTC, acting as a transaction manager, controls the transaction. Individual
databases participate in the transaction through their own resource manager that guarantees the
atomicity of actions on a single database and responds to commands from MSDTC. MSDTC is
responsible for the ACID attributes of the entire distributed transaction, whereas the resource
managers are responsible for the ACID attributes of each individual database.
MSDTC embodies all the function points necessary to perform two-phase commit protocol
across databases. MSDTC can be both a transaction manager and a resource manager. COM+
allows you to start and stop the service directly from the Component Services explorer. Figure
7.1 shows the MyComputer menu in the explorer for managing the MSDTC.
Data Services
184
PART II

FIGURE 7.1
Use the pop-up menu in the Component Services Explorer to start and stop MSDTC.

Transactional Components
Transaction support is greatly simplified under COM+ through the use of transactional compo-
nents. Transactional components are business objects that operate inside transactional contexts.
These business objects are the same Visual Basic ActiveX DLLs that you create for any appli-
cation; however, COM+ allows transactions to be performed across the methods of these
objects.
Designating a transactional component inside COM+ is done by setting the declarative attrib-
utes for the component in the Component Services explorer. The properties sheet is accessed
by clicking an object and selecting Properties from the Action menu. The Transactions tab of
the properties sheet contains the transaction property options for the selected object. COM+
supports five mutually exclusive transaction options:
• Required causes COM+ to include the object in a transaction context every time a
method in the object is called. If a specific transaction isn’t available for the object,
COM+ starts a new one.
• Requires New causes COM+ to start a new transaction each time the object is invoked by
a client, regardless of what other transactions are in progress.
• Supported allows COM+ to run the object in a transaction if requested, or alone if no
transaction is required.
• Not Supported means that COM+ will never run the object in a transaction context.
• Disabled specifies that no transactional context will be created for the component, which
eliminates transactional overhead for that component.
COM+ Transactions
185
CHAPTER 7

Beginning with Visual Basic 6.0, you can also set the transactional properties for a component
directly in the properties sheet. Each class in an ActiveX component supports the
MTSTransactionMode property. If you set this property, the correct setting will automatically
appear in the COM+ Explorer when the component is added to a package. If you don’t put the
class in a package, the property has no effect.

NOTE
The MTSTransactionMode property in Visual Basic 6 was designed to work with the
transactional settings found in the Microsoft Transaction Server (MTS). Because MTS 7
doesn’t support a setting of “disabled,” you won’t find this value available in Visual

TRANSACTIONS
Basic. If you want transactions disabled for the component, set the property explicitly

COM+
in COM+.

When a component is designated to be inside a transaction, COM+ uses the MSDTC to coordi-
nate a transaction between the Resource Managers and Resource Dispensers that perform the
work called by the code in the transactional component. Resource Managers manage the state
of persistent resources, such as database information, whereas Resource Dispensers manage
non-persistent resources, such as database connections. In either case, when your business
object invokes a Resource Manager or Resource Dispenser from a transaction, the MSDTC
serves as the transaction manger responsible for ensuring the ACID attributes of the transaction
across all involved resources.
The COM+ Explorer provides a special view that shows the transactional attributes of compo-
nents without having to specifically examine the properties sheet. This view, aptly enough, is
called the Property View. You can shift the explorer view to Property View by selecting
Property View from the View menu. The Property View shows not only the transactional attrib-
utes, but also other key object information such as the CLSID and the threading model sup-
ported by the object. Figure 7.2 shows the Property View in the Component Services explorer.

Understanding Transaction Context


COM+ manages objects involved in a transaction through the transaction context. The transac-
tion context defines whether work done by different objects should be considered part of the
same transaction. When objects share transaction context, all their work must succeed or fail as
a batch and the ACID attributes of a transaction be maintained.
When programming transactions in COM+, you need to understand the transaction context
associated with a particular object. The context is determined by the transaction property of the
object as set in the Component Services explorer. Objects designated to always begin a new
Data Services
186
PART II

transaction will never inherit the transaction of any other object. The context for these objects
is new each time the object is called. Objects that support transactions can inherit the context
of another object and thus participate in the overall transaction. If an object doesn’t support
transactions, it can’t inherit transaction context or participate in any transaction.

FIGURE 7.2
The Property View shows key settings for each component.

On the surface, the concept of using declarative attributes to handle transactions seems rela-
tively straightforward. In practice, however, planning is required to arrive at a design that
works well in various situations. Perhaps the most important issue in the design of a transac-
tional system is properly establishing the transactional boundary.
Transactional boundary maps the initiation and committal of a transaction to method calls
within components. In other words, what method in which class will initiate the transaction?
What additional classes will participate in the transactions? The answers to these questions
form the transactional boundary of the system.
In my experience, developers new to distributed systems often attempt to define the transac-
tional boundary within the data services layer. Quite often we find that systems are designed
with a coarse data component encapsulating all data access. This coarse component is then
designated with a transactional attribute of Required. In that way, every operation performed
by the system is part of a transaction. Figure 7.3 shows a conceptual drawing of this
architecture.
COM+ Transactions
187
CHAPTER 7

Transactional Boundary

A single
method is
invoked for all
data access

Data Component Database

Single data component


7
performs all write operations

TRANSACTIONS
to the database

COM+
FIGURE 7.3
Coarse data components act as the transactional boundary.

In Chapter 6, “COM+ Data Components,” I discussed performance problems associated with


coarse data components. In addition to these problems, coarse data components also present
problems with transactional design. Because a single component performs all write operations,
I often find that these systems rapidly decay into a monolithic application with little or no par-
titioning between tiers.
Consider the process of ordering books from an online store. To complete the transaction that
eventually results in shipping a book, the site needs to perform three operations: verify that the
requested book is in stock, authorize the credit card, and verify the shipping address. If any of
these pieces of information is missing, the transaction can’t be completed.
In the case of a coarse data component, this would require three calls to the component. Each
call would perform one of the three operations. However, because the transactional boundary
encompasses the entire coarse data component, each of the three operations represents a sepa-
rate transaction. There’s no way to tie all three operations together into a single transaction.
Figure 7.4 shows a conceptual drawing of this problem.
Your reaction to this problem might be to suggest that all the necessary information be sent to
the data component at once. Rather than make three separate calls, why not just make a single
call with book, credit card, and shipping address information all included? At first this idea
seems reasonable because the transactional boundary will be crossed only a single time. Figure
7.5 shows a conceptual drawing of this architecture.

Although passing all the data in this way will allow the transaction to work correctly, it leads
to a poor definition of tiers, which destroys maintainability. This happens because no matter
how you set it up, your system must still perform three write operations to complete the trans-
action. Therefore, the coarse data component can at times be performing a single operation,
Data Services
188
PART II

whereas at other times it will perform multiple operations. This means that you must program
logic into the component to handle the transaction. This defeats the entire purpose of declara-
tive transactional attributes.

Transactional Boundary

Book Title

Credit Card Books

Payments

Shipping Address
Addresses

Data Component Database

Each time the transactional boundary is crossed, a new


transaction begins

FIGURE 7.4
Coarse data components require separate transactions for each call.

Transactional Boundary

Book Title
Credit Card Books
Shipping Address
Payments

Addresses

Data Component Database

FIGURE 7.5
Crossing the transactional boundary a single time improves the design.

In response to this, you might also be tempted to perform the transaction as a single operation
managed by a stored procedure in SQL Server. This is certainly possible. You could use the
Transact-SQL BEGIN TRANSACTION command to perform the three operations and handle errors
with a rollback. SQL Server can even engage the MSDTC for two-phase commit directly from
Transact-SQL.
COM+ Transactions
189
CHAPTER 7

The problem here is that you are now pushing the transactional boundary into the database
itself. Undoubtedly, the next thing you will do is begin to code business logic into these proce-
dures and you will soon find that you are writing a large portion of your application in
Transact-SQL. This is no better than a simple client/server design.
So what’s the correct way to architect a transactional boundary in a COM+ system? Move the
transactional boundary out of the data services layer and into the business services layer.
Remember, the data components are intended to be ignorant slave components that don’t know
the nature of the transaction being performed. Instead, they participate in transactions and sim-
ply write the data as instructed by the business services layer. 7
In our designs, we typically create a business component for each business process in the

TRANSACTIONS
application. In this system, we might create a business component to manage orders. The busi-

COM+
ness component would initiate and control the transaction, and it would have its transactional
attribute set to Requires New. In the data services layer, we would break up the coarse compo-
nent into three fine-grained components. Each write operation would be handled by a separate
data component, and each component would have its transactional attribute set to Required. In
this way, the write operations performed by the data components would all fall into the trans-
action initiated by the business component. Figure 7.6 shows a conceptual drawing of this
architecture.

Transactional Boundary

Data
Component
Book Title Business
Credit Card Component Books
Shipping Address Data
Component Payments

Addresses
Data
Transactional Component
attribute set to
Requires New Database

Transactional attributes set to


Required

FIGURE 7.6
The business services layer initiates and controls transactions.

Moving the transactional boundary to the business services layer and creating fine-grained data
components has several advantages:
Data Services
190
PART II

• The business logic necessary to control the transaction resides in the business services
layer separated from the data access code. This means that the transactional logic can
be changed without affecting the data access components. This can’t be said for coarse
components.
• Fine-grained data components can be accessed by other business components to create
new transactional capabilities without rewriting the data components. Because the data
components are ignorant of the logic controlling the transaction, they will happily partic-
ipate in any transaction initiated by any business component.
• The improved partitioning of the tiers simplifies component design and construction,
making it easier to build the system. Once you understand the high-level architecture for
creating transactional systems in COM+, you are ready for the specifics of how to code
such transactions.

Key Principle
Always set the transactional boundary in the business services layer. Business services
components should set their transactional attribute to Requires New. Always use fine-
grained data components with transactional attributes set to Required.

Voting in Transactions
Components that have their transactional attributes set to provide transactional support partici-
pate in the transaction by inheriting transactional context and voting within the transaction.
Transactions begin when any method of a component marked as Required or Requires New is
called. The simple act of calling a method causes COM+ to contact the MSDTC and begin a
new transaction. The component that starts the transaction controls the transaction. The con-
trolling component then enlists other components in the transaction by creating an instance of
the component and calling any method. Each component involved in the transaction can then
vote for the success or failure of the transaction. If all components, including the controlling
component, vote for success, the transaction commits. If any component votes for failure, the
entire transaction is rolled back. Figure 7.7 shows a flowchart for a transaction involving a
book purchase.

In practical terms, components can vote in a transaction automatically or manually. Automatic


transactions vote for success or failure based on whether a runtime error occurs within the
method. Manually, voting is accomplished through the SetComplete and SetAbort methods of
the context. Each voting method has strengths and weaknesses that you need to understand
before deciding how to design your system.
COM+ Transactions
191
CHAPTER 7

Book, Credit Card, and Shipping


Address sent to business
component

MSDTC contacted
and new
transaction begins

First data
component called
to write book
information to
7
database

TRANSACTIONS
COM+
Success?

Yes

Vote for
Transaction
commit

Second data
component called
to write credit card
No
information to
database

Success?
No
Yes MSDTC Rolls
Back Transaction

Vote for End


Transaction
commit
No MSDTC Commits
Transaction
No
Third data
component called
to write address
information to
database

Yes

Success? Success?

Yes

Business
Vote for
component
Transaction
completes
commit processing

FIGURE 7.7
Each component votes in a COM+ transaction.
Data Services
192
PART II

Automatic Transactions
I’ve already discussed that every object activated within COM+ is contained within a context.
Previous chapters examined how the context helps support efficient activation and deactivation
of object instances. In addition to these functions, the context also contains the transactional
context and voting mechanism for a COM+ component.
Every context in COM+ contains two key bits that determine how activation and transactional
processing proceed: the done bit and the consistency bit. The done bit determines whether an
object is deactivated after the current method call, whereas the consistency bit determines
whether a component votes for success in the current transaction.
The done bit has a default value of False. This means that objects normally aren’t deactivated
when they return from a method call. If you enable the Auto Done feature for any given com-
ponent, COM+ ensures that the done bit is set to True when the designated method returns.
You can also set the done bit to True by calling the SetComplete or SetAbort method of the
context. Either approach will deactivate the instance when the current method returns.
The consistency bit works similarly. The default value for the consistency bit is True. This
means that if you do nothing, your component will vote to commit the current transaction
when it returns from the current method call. The exception is that the consistency bit will
automatically be set to False if an unhandled error is generated during the current method call.
This means that unhandled errors cause transactions to roll back, whereas successful comple-
tion of a method causes transactions to commit.

QUICK CHECK 7.1

Automatic Transactions
1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 07\Quick Check 7-1. This directory contains a project you can use
to investigate automatic transactions.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 7-1. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Before we investigate the project, we must create a SQL Server database for use with the
exercise in this chapter. To create the database, open the SQL Enterprise Manager and
expand the tree to expose the databases folder. With the databases folder open, select
New Database from the Action menu. Name the new database COMBank. Figure 7.8
shows the Database Properties dialog.
COM+ Transactions
193
CHAPTER 7

TRANSACTIONS
COM+
FIGURE 7.8
Create a new database named COMBank.

4. After the new database is created, open the SQL Server Query Analyzer from the Tools
menu. Be sure to select the COMBank database from the list of available databases. Figure
7.9 shows the Query Analyzer.

FIGURE 7.9
Open the SQL Server Query Analyzer.

5. Locate the SQL script file combank.sql and open it in the Query Analyzer. This script
will create a table called Accounts and populate it with data for the exercise. Run this
script on the COMBank database.
6. Open the project named autotrans.vbp. This project contains a business component
named Manager and two data components named Reader and Writer. The Manager class
is marked to require a new transaction, and the Reader and Writer classes require a trans-
action. In this project, the Manager class is used to transfer money between accounts. It
Data Services
194
PART II

initiates and manages a transaction and calls the Reader and Writer as necessary to con-
trol the process.

NOTE
The connect string used in this exercise assumes that SQL Server is set up on the same
machine as the component and uses standard security. You might have to change this
string if your setup is different.

7. Compile the project into an ActiveX DLL.


8. Create a new COM+ application for the three classes named Auto Transactions. Place the
Manager, Reader, and Writer classes into the same COM+ application.
9. Using the Component Services explorer, enable the Auto Done feature for the methods of
each class.
10. Locate the file client.hta. This is a page that allows you to transfer money between
accounts in the database. When you start the page, it has a debit and credit account filled
in for you. Figure 7.10 shows the page.

FIGURE 7.10
Use this page to test transactions.
COM+ Transactions
195
CHAPTER 7

11. Use the page to transfer money between accounts. Initially, it should work fine. Then try
entering a bad account ID. This time the transaction will fail. COM+ is managing all the
database operations to enforce the ACID requirements for transactions.

NOTE
Be sure to close and reopen the page after you attempt transfers with any bad
account numbers. If you don’t, you might experience unexpected error messages.

7
Quick Check 7.1 should convince you that automatic transaction will work in COM+; however,

TRANSACTIONS
we have to be careful with unhandled errors. Although it’s true that unhandled errors will cause

COM+
transactions to abort, they can also prevent your object from being deactivated properly.
Therefore, you might want to consider using error handlers in your components along with
manual voting.

Manual Transactions
If you are concerned about the proper deactivation of object instances because of unhandled
errors, your first thought might be to place error handlers within your classes and then return
error information as part of the payload. This idea seems sensible; however, error handlers pre-
vent the consistency bit from changing to false. This is because a handled error doesn’t look
like an error to COM+. This means that classes with error handlers will always vote to
commit in any automatic transaction. This can have frightening results, as Quick Check 7.2
demonstrates.

QUICK CHECK 7.2

Error Handling in Automatic Transactions


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 07\Quick Check 7-2. This directory contains a project you can use
to investigate error handling in automatic transactions.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 7-2. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Open the project named autotrans2.vbp. This project contains the same classes as you
worked with in Quick Check 7.1 except that I have placed error handlers in the classes.
Data Services
196
PART II

NOTE
The connect string used in this exercise assumes that SQL Server is set up on the same
machine as the component and uses standard security. You might have to change this
string if your setup is different.

4. Compile the project into an ActiveX DLL.


5. Create a new COM+ application for the three classes named Auto Transactions 2. Place
the Manager, Reader, and Writer classes into the same COM+ application.
6. Using the Component Services explorer, enable the Auto Done feature for the methods of
each class.
7. Locate the file client.hta. This is the same page you used in Quick Check 7.1.
8. Begin by transferring money and noting the value of each account. Figure 7.11 shows the
balances for our accounts when we ran the code.

FIGURE 7.11
Note the values of the accounts after a transfer.

9. Enter an incorrect account number for the credit account only and attempt a transfer. The
balances for the debit account will reflect a debit, but the credit account will show zero.
COM+ Transactions
197
CHAPTER 7

Money has disappeared! Figure 7.12 shows the client page when the half transaction
completes.

TRANSACTIONS
COM+
FIGURE 7.12
Half of the transaction completed.

Using error handlers in your classes while depending on automatic transactions can easily set
up a situation in which transactions complete in clear violation of the ACID properties. If this
application were mission-critical, valuable data could be lost forever, even though you used
what appeared to be a sound architecture. We must find a solution that properly deactivates
objects while maintaining a high level of confidence that transactions will be handled correctly.
The solution to this problem is to use the SetComplete and SetAbort methods of the context.
If you’re attempting to learn COM+ on your own, you might be led by various magazine arti-
cles and MSDN help to believe that support for SetAbort and SetComplete is only for back-
ward compatibility with MTS components. However, I’ve proven that you can’t yet rely on the
automatic features of COM+.
SetAbort and SetComplete are used within your code to manually set the done and consis-
tency bits. Understanding their effect on these bits can help you guarantee proper functionality.
First, I’ll discuss the done bit. Remember that when the done bit is set to True, the object is
deactivated after the current method call completes. The done bit will be set to True by calling
SetAbort or SetComplete.
Data Services
198
PART II

On the other hand, each method affects the consistency bit differently. Calling SetComplete
sets the consistency bit to True, whereas calling SetAbort sets the consistency bit to False. In
this way, you can ensure proper deactivation and transaction outcome. Table 7.1 shows the
effect of calling SetComplete or SetAbort on both the done and consistency bits.

TABLE 7.1 Values for Done and Consistency Bits


Method Done Bit Consistency Bit
SetComplete True True
SetAbort True False

Key Principle
If you design for automatic transactions, don’t place error handlers in your compo-
nents. If you use error handlers in transactional components, you must use the
SetComplete and SetAbort methods to guarantee the correct behavior.

Monitoring Transactions
While transactions are running under COM+, you can monitor the state of each transaction as
well as view statistics regarding the success and failure of each transaction. In the Component
Services explorer, transactions can be monitored for any computer in the explorer. Simply
select the desired computer and then click the Transaction Statistics icon under the Distributed
Transaction Coordinator folder. In this view, you can see statistical information regarding the
success and failure of previous transactions. Figure 7.13 shows the statistics.

While transactions are running, you might occasionally have to resolve a transaction manually.
Transactions can be viewed and resolved manually using the Transaction List view in the
Component Services explorer. Using this view, you can monitor the state of each running
transaction. Transactions that are in an undefined state because of system resource failure can
be manually committed or failed by selecting them in the explorer and right-clicking for a con-
text menu. Transactions can be in an undefined state when MSDTC prepares all the system
Resource Managers, but then fails unexpectedly. In this state, Resource Managers are awaiting
a commit or abort command from the Transaction Manager, but it’s unavailable.
COM+ Transactions
199
CHAPTER 7

TRANSACTIONS
COM+
FIGURE 7.13
View transaction statistics for MSDTC.

EXERCISE 7.1

COM+ Transactions
After examining the various ways to create transactional systems, we build a system using
error handlers and manual voting. This exercise gives you a good example of how to construct
transactional components. You can use much of the code in the exercise as a starting point for
your own applications.
Creating the COM+ Components
Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
07\Exercise 7-1. This directory contains a partially completed project that you can use to
investigate transactions in COM+.

Step 2
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
7-1. Copy the contents from the CD-ROM directory into the new directory you just created.
Data Services
200
PART II

Step 3
Open the project named manualtrans.vbp. This project contains the same three class modules
used in the Quick Check exercises. The difference is that we will use the context to control
deactivation and transactional behavior.

Step 4
Open the class named Writer. This class contains a method named AdjustBalance, which
updates the balance of any account. Add the code in Listing 7.1 to the method.

LISTING 7.1 The AdjustBalance Method


On Error GoTo AdjustBalanceErr

‘Context code
Dim objContext As COMSVCSLib.ObjectContext
Set objContext = GetObjectContext()

‘Variables
Dim objConnection As ADODB.Connection
Dim strConnect As String
Dim strSQL As String

‘Update account balance


Set objConnection = New ADODB.Connection
strConnect = “Provider=SQLOLEDB;Data Source=(local);”
strConnect = strConnect & “Initial Catalog=COMBank;UID=sa;PWD=;”
strSQL = “UPDATE Accounts SET AccountBalance = AccountBalance + “ _
& curAmount & “ WHERE AccountId = ‘“ & strAccountID & “‘“
objConnection.Open strConnect
objConnection.Execute strSQL

‘Tell COM+ we succeeded


objContext.SetComplete

AdjustBalanceExit:
Exit Sub

AdjustBalanceErr:

‘Tell COM+ we failed


objContext.SetAbort

‘Log Error
Debug.Print Err.Description
App.StartLogging App.Path & “\error.log”, vbLogToFile
App.LogEvent Err.Description, vbLogEventTypeError
Resume AdjustBalanceExit
COM+ Transactions
201
CHAPTER 7

NOTE
The connect string used in this exercise assumes that SQL Server is set up on the same
machine as the component and uses standard security. You might have to change this
string if your setup is different.

Step 5
Open the class named Reader. This class contains a method named GetBalance, which reads
7
the balance of any account. Add the code in Listing 7.2 to the method.

TRANSACTIONS
COM+
LISTING 7.2 The GetBalance Method
On Error GoTo GetBalanceErr

‘Context Code
Dim objContext As COMSVCSLib.ObjectContext
Set objContext = GetObjectContext()

‘Variables
Dim objRecordset As ADODB.Recordset
Dim strConnect As String
Dim strSQL As String

‘Run Query
Set objRecordset = New ADODB.Recordset
strConnect = “Provider=SQLOLEDB;Data Source=(local);”
strConnect = strConnect & “Initial Catalog=COMBank;UID=sa;PWD=;”
strSQL = “SELECT AccountBalance From Accounts WHERE AccountID=’” _
& strAccount & “‘“
objRecordset.Open strSQL, strConnect

‘Return Balance
GetBalance = objRecordset!AccountBalance

‘Tell COM+ we succeeded


objContext.SetComplete

GetBalanceExit:
Exit Function

GetBalanceErr:

continues
Data Services
202
PART II

LISTING 7.2 Continued


‘Tell COM+ we failed
objContext.SetAbort

‘Return Value
GetBalance = -1

‘Log Error
Debug.Print Err.Description
App.StartLogging App.Path & “\error.log”, vbLogToFile
App.LogEvent Err.Description, vbLogEventTypeError
Resume GetBalanceExit

Step 6
Open the class named Manager. This class initiates and controls the transaction. It will call the
Writer class once for the debit operation and once for the credit operation. The Manager class
contains a method named Transfer. Add the code in Listing 7.3 to this method.

LISTING 7.3 The Transfer Method


On Error GoTo TransferErr

Dim objContext As COMSVCSLib.ObjectContext


Set objContext = GetObjectContext()

‘Variables
Dim objWriter As ManualTrans.Writer
Dim objReader As ManualTrans.Reader
Dim curDebit As Currency
Dim curCredit As Currency
Dim vReturn As Variant

‘Create instances with CreateObject


‘because classes are in the same DLL
Set objWriter = CreateObject(“ManualTrans.Writer”)
Set objReader = CreateObject(“ManualTrans.Reader”)

‘Move the Money


objWriter.AdjustBalance strDebitAccount, -1 * curAmount
objWriter.AdjustBalance strCreditAccount, curAmount

‘Get new Balances


curDebit = objReader.GetBalance(strDebitAccount)
curCredit = objReader.GetBalance(strCreditAccount)
COM+ Transactions
203
CHAPTER 7

‘Return Values
vReturn = Array(curDebit, curCredit)
Transfer = vReturn

‘Tell COM+ we succeeded


objContext.SetComplete

TransferExit:
Exit Function

TransferErr:
‘Tell COM+ we failed
7
objContext.SetAbort

TRANSACTIONS
COM+
‘Return values
vReturn = Array(-1, -1)
Transfer = vReturn

‘Log error
Debug.Print Err.Description
App.StartLogging App.Path & “\error.log”, vbLogToFile
App.LogEvent Err.Description, vbLogEventTypeError
Resume TransferExit

Step 7
Compile the project into an ActiveX DLL. Create a new COM+ application for the three
classes named Manual Transactions. Place the Manager, Reader, and Writer classes into the
same COM+ application.

Step 8
Using the Component Services explorer, enable the Auto Done feature for the methods of each
class.
Creating the Front End
Step 9
Locate the file client.hta. This is the same page used in several of the Quick Check exer-
cises, but we will code the <SCRIPT> section. Open the file in Notepad.

Step 10
In the client.hta file is an event named cmdTransfer_OnClick. This event calls the Manager
to initiate the transaction. Add the code in Listing 7.4 to this event.
Data Services
204
PART II

LISTING 7.4 The OnClick Event


Dim vReturn
Dim strDebit
Dim strCredit
Dim curAmount

strDebit = document.all.txtDebit.value
strCredit = document.all.txtCredit.value
curAmount = Ccur(document.all.txtAmount.value)

‘Transfer Money!
vReturn = objManager.Transfer(strDebit,strCredit,curAmount)

‘Display Balances
document.all.lblDebit.innerText = CStr(vReturn(0))
document.all.lblCredit.innerText = CStr(vReturn(1))

Step 11
Try transferring money and verify that the application works correctly. Then try entering
bad account numbers. The transaction should fail. Also examine the Property View for the
components; you should see that they are properly deactivated whether or not the transaction
succeeds.
PART
Business Services
III
IN THIS PART
8 COM+ Security 207

9 COM+ Business Features 231

10 Asychronous COM+ Applications 255


COM+ Security CHAPTER

8
IN THIS CHAPTER
• Distributed Security 208

• Active Directory 210

• Active Directory Services Interface 213

• COM+ Security Features 222

• Conclusion 226
Business Services
208
PART III

Security breaches in distributed systems certainly make for great headlines. From denial-of-
service attacks to the Melissa and ILOVEYOU viruses, we’ve clearly witnessed how important
security is to the modern network. Unfortunately, we are often our own worst enemy.
Case in point: Recently, an online retailer experienced a security violation resulting in the loss
of thousands of credit cards from its databases. The hacker who had retrieved the data sent a
ransom message to the retailer demanding cash, or the credit card numbers would be posted on
the Internet. When the retailer refused to pay and contacted the FBI, the credit cards were
posted for anyone in the world to use.
In the aftermath of the event, MSNBC did a story about database security on the Web. As part
of the story, they used the SQL Server Enterprise Manager to attempt access to databases on
the Web. To everyone’s shock, MSNBC was able to retrieve thousands of credit card numbers
from several retailers by simply using sa and no password!
The lesson of this event is that developers can no longer afford to simply be “code jockeys”
with no knowledge of networking infrastructure or security concerns. Building distributed
applications demands a good working knowledge of the network and a strong respect for secu-
rity. This chapter certainly won’t make you a network engineer, but I present an overview of
the areas you need to know along with solid techniques for implementing security in COM+
applications.

Distributed Security
Historically, network security has relied on a simple system of usernames and passwords.
When a client entered a valid combination of name and password, access was granted to the
system. However, distributed computing environments have special security needs that tran-
scend simple user and password systems. For example, usernames and passwords entered by
the client might help a network server identify the client, but the client has no guarantee that
the server is authentic.

Certificates
One method of attacking the security of a distributed system is to impersonate a network
server. Impersonating a server allows an illegitimate server to receive usernames and pass-
words from clients on the network. These usernames and passwords can then be used to gain
access to other network resources.
Public key encryption offers a vastly superior method for authenticating both the client and
server. Under this system, both the client and the server have a pair of keys: one is public and
the other private. Public keys are available to any resource, but they can be used only to
encrypt data. Private keys are restricted to a single resource and are used to decrypt the data.
COM+ Security
209
CHAPTER 8

The process of accessing a resource using keys begins when the client uses the server’s public
key to encrypt data such as a username and password. Because the server’s public key is avail-
able to any resource, the client can encrypt the data and send it to the server. Decrypting the
data can be accomplished only with the private key, which is held only by the authentic server.
This system prevents impersonation attacks because the impersonating server won’t have
access to the private key of the authentic server.
The client also can provide additional security by digitally “signing” the data that was
encrypted with the public key. Signing the encrypted data is done using the client’s private key.
The server can then verify the client’s identity by using the client’s public key. Figure 8.1
shows a conceptual diagram of this process.

Server Server
Public Key Private Key

Username Username
1101101011011 Network 1101101011011
Password 0000011011101 0000011011101 Password

Client Signature Client Signature


Client Signature Signature Server
8

COM+ SECURITY
Client Private Client Public
Key Key

FIGURE 8.1
Key pairs guarantee the identity of both client and server.

Although servers can use keys to prevent impersonation, they work only when you can trust
the source of the key. Anyone can create keys, so you must indicate on the network which
sources are trusted. This is done using the Certificates snap-in for the Microsoft Management
Console (MMC). You can access this snap-in by running the MMC and selecting to add a snap-
in from the Console menu. Figure 8.2 shows the Certificates snap-in.

Kerberos Protocol
Certificates provide a mechanism for guaranteeing that the machines exchanging data are legit-
imate. However, each time a user wants to access a resource, the network must verify that
user’s permissions. This requires an underlying authentication protocol that’s appropriate for
distributed systems. The underlying security model is constructed based on the Security
Support Provider Interface (SSPI), which provides a mechanism for making authenticated con-
nections. SSPI is intended to be a platform-independent security standard.
The Microsoft Windows NT LAN Manager Security Support Provider (NTLMSSP)
was used under Windows NT to make authenticated connections in the distributed network
environment. The primary mechanism for authenticating users in this environment was the
Business Services
210
PART III

challenge-response system. In this system, the server would send a package of data to the client
as the “challenge.” The client would respond by encrypting the data and sending it back to the
server, where it was compared with the original data for consistency.

FIGURE 8.2
Windows 2000 is configured with several certificates by default.

Under Windows 2000, the default protocol for authentication is Kerberos 5, a more secure pro-
tocol than NTLMSSP. Kerberos also supports delegation and impersonation. This means that a
client’s credentials can be used by another service to gain access to network resources through
a process known as cloaking.
The Kerberos protocol is based on the concept of a ticket. A ticket is issued by a Key
Distribution Center (KDC) and allows a client machine to request access to network resources.
Each domain controller in Windows 2000 can act as a KDC. A domain controller is established
when you promote a Windows 2000 server by installing the Active Directory.

Active Directory
Active Directory represents the central exhibit in Windows 2000’s security architecture.
Active Directory is a total replacement for the Windows NT Security Accounts Manager
(SAM) that’s completely integrated with network services. Using Active Directory in your
COM+ Security
211
CHAPTER 8

COM+ applications gives you a standard way to implement security and personalization fea-
tures that once required you to create a custom application security system. Using Active
Directory will allow you to create applications that work under the single sign-on (SSO) sys-
tem, are deployable using the Microsoft Installer (MSI), and can be personalized for each
end user.

Single Sign-On
Although many development teams don’t have strong networking and security knowledge,
almost all of them acknowledge the need for some type of authentication. Typically this entails
forcing the user to enter a name and password when the application starts. In most cases, this
application login is in addition to the network login the user already performed. For the appli-
cation user, this often means having to remember multiple passwords. Single sign-on is a con-
cept that relieves the user from the burden of remembering multiple passwords by simply
utilizing the network credentials for access to applications and other services.
In the past, SSO has been difficult to achieve because Visual Basic programmers had no easy
way to retrieve application-level permissions for users. Instead, most developers created a cus-
tom security database with their own usernames, passwords, groups, and permissions. This 8
database was independent of the SAM and therefore required a separate login by the client

COM+ SECURITY
when the application started.
Active Directory eliminates the need for custom security databases. Active Directory is easily
accessible from Visual Basic components and contains all the information necessary to deter-
mine the level of authority for an application user. All applications written for Windows 2000
should use Active Directory as the security database.
Microsoft supports the concept of SSO in Windows 2000 by integrating the network services
with Active Directory. For example, the newest version of Microsoft Exchange is integrated so
that mailbox information is kept in Active Directory. This means that administrators have only
one profile to manage for network users. It also means that programmers have access to key
information such as email addresses for all users. Figure 8.3 shows a typical profile with
Microsoft Exchange information incorporated.

Microsoft Installer
The Microsoft Installer (MSI) service first shipped with Office 2000. MSI creates an improved
installation system for the entire network. Although I will discuss MSI in more detail in
Chapter 14, “Debugging and Distributing COM+ Applications,” it’s important to recognize that
Active Directory supports distribution of your applications through MSI and group policies.
Business Services
212
PART III

FIGURE 8.3
SSO integrates user information for all applications.

Group policy is an Active Directory concept that allows a network administrator to specify the
software that should be available on any user’s desktop. Creating a new group policy and then
associating the MSI installation files with that policy defines the corporate desktop. Once
established, the group policy will automatically install the application software the next time a
user logs in.

Personalization
The Active Directory not only acts as a repository for permissions, but also contains profile
information for application users. Active Directory contains fields for name, address, phone
numbers, email, and many others. This means that Active Directory is appropriate not only for
authorized network users, but also for Internet communities. Active Directory is, for example,
scalable enough to be the repository of all customer information for an e-commerce retailer.
As a COM+ programmer, you can gain access to all the information stored within Active
Directory and use it to personalize your applications. This permits you to create sites, for
example, that welcome customers by name and make suggestions for purchasing. All of this is
made possible because Microsoft has provided an object interface to Active Directory known
as the Active Directory Services Interface (ADSI). Figure 8.4 shows a user profile with some
examples of available information.
COM+ Security
213
CHAPTER 8

FIGURE 8.4
Active Directory contains information useful in personalizing applications.
8

COM+ SECURITY
Active Directory Services Interface
ADSI is the object interface to the information in the Active Directory, which you will use
extensively in your COM+ applications. Although ADSI contains dozens of objects, the truth is
that you can go a long way with just a few objects. A full treatment of all ADSI objects is
beyond the scope of this book, but I’ll give you the fundamentals you’ll need to perform secu-
rity and personalization functions within your applications.

Using ADSI
Before you can begin to use ADSI, you must first understand the concept of a pathname.
Pathnames in Active Directory are similar to pathnames on the Internet or in the file system.
Pathnames help you navigate the hierarchical data structures of the Active Directory to locate
the information you need. Although there are several different forms for a pathname, in all
cases you must explicitly know the name of the domain, group, and object you want to access.
Paths in LDAP are similar to a uniform resource locator (URL) on the Internet. In this case,
you begin with the name of the protocol you want to use followed by information indicating
the location of the resource. Because Active Directory runs as a service similar to a Web
server, you can access the Active Directory just the same way you might access a Web page.
Business Services
214
PART III

The protocol used by Active Directory is the Lightweight Directory Access Protocol (LDAP), a
command-response protocol used by clients to retrieve information from a directory service.
This is exactly analogous to using the Hypertext Transfer Protocol (HTTP) in a browser to
access a Web page under Internet Information Server (IIS). Therefore, the path name for Active
Directory begins just like a Web address—protocol followed by server name. The following
code shows a URL for the root of a Web server followed by an LDAP path for the root of
Active Directory:
http://scotwin2k
ldap://scotwin2k

The similarities between Active Directory and IIS continue with both services running on a
specified port. The default port number for Web services is port 80, and the default port for the
LDAP service is port 389. Although many people don’t realize it, you can append a port num-
ber to a Web path by using a colon. So the following code is also a valid path that you can type
into a browser:
http://scotwin2k:80

By default, the browser always communicates with port 80, so there’s usually no need to
include a port number in the path. However, if you want to access Active Directory from your
browser, you can take advantage of the port number to specify that the browser should commu-
nicate with the LDAP service. Figure 8.5 shows the results of entering an LDAP path into the
Internet Explorer browser.

FIGURE 8.5
The Internet Explorer can access the LDAP service directly.

Accessing the LDAP service from the browser causes a search screen to appear that will let
you search the Active Directory for people in the organization. This same dialog appears when
you select Search from the Start menu in Windows 2000. It’s also the same mechanism used to
search directory services on the Internet.
COM+ Security
215
CHAPTER 8

Pathnames in Active Directory must be unique to guarantee that you can locate the information
you want. However, nothing prevents you from adding objects to the directory that have the
same name. For example, you could easily add a computer to Active Directory that has the
same name as a user. Because of this, pathnames for a directory use a distinguished name
(DN) to uniquely identify them. A DN combines attributes that form the complete path to the
object in Active Directory. Using LDAP attributes to create a DN results in a path that looks
quite a bit different from the URL format we are used to. The following shows the LDAP path
for the domain administrator:
LDAP://CN=Administrator,CN=Users,DC=dc,DC=local

In this path, notice that each level in the hierarchy is preceded by an attribute identifying it. CN,
for example, is the common name for the object in Active Directory. DC stands for domain
component. Each name corresponds to a level in the directory hierarchy. This hierarchical
structure extends throughout the Internet and is the source of the URL naming conventions we
are all familiar with. For example, com is actually a domain component, as is Microsoft. When
we want to visualize domains, we often show them as triangles in a domain hierarchy. Figure
8.6 shows how domains are designated on the Internet.
8

COM+ SECURITY
Root

.com .org

microsoft.com sun.com npr.org

FIGURE 8.6
Directories are hierarchical on the Internet.
Business Services
216
PART III

Within any DC, you can also find organizations (O) and organizational units (OU). These divi-
sions represent sub parts of the directory within the enterprise and are created when you add
new folders to Active Directory. A complete DN might consist of references to any number of
DC, O, OU, and CN elements depending on where it is in the structure. Also notice that the DN is
created in reverse hierarchical order beginning with the lowest-level CN. Table 8.1 lists the
common attributes of a path.

TABLE 8.1 LDAP Path Attributes


Attribute Definition
DC (domain component) A registered domain name
O (organization) A company enterprise spanning a wide area network
OU (organization unit) A division within a company enterprise
CN (common name) The name of any object in the directory

The good news about LDAP paths is that after you figure them out, accessing objects in the
Active Directory is simple. For Visual Basic programmers, all you need is the correct path and
the GetObject() function. With the GetObject() function, you can easily return a reference to
the object you specified in the Active directory. The following code shows how to use a single
Variant to reference the Administrator object for the domain xyz.com:
Set MyObject = GetObject(“LDAP://CN=Administrator,CN=Users,DC=xyz,DC=com”)

Manipulating Properties
Once you have the reference to an object, you might be wondering what you do with it. The
answer is that you can now read information for the purpose of identifying permissions and
personalizing the application. ADSI allows you to access almost any information contained in
Active Directory for the selected object.
Although you can use the simple code shown previously to connect to an object, you will prob-
ably want to set a reference in Visual Basic to ADSI so that you can use the specific objects
and interfaces by name. ADSI supports dozens of objects and interfaces that allow you to
manipulate users, groups, and computers. Figure 8.7 shows the Visual Basic references dialog
with the ADSI reference set.
Once you have a reference set, you can declare ADSI objects by name. The most basic of all
ADSI objects is IADs, which you use to connect to a specific object. The following code
shows how to connect to the Administrator object in the domain DC.LOCAL:
Dim objADSI As ActiveDs.IADs
Set objADSI = GetObject(GetObject _
(“LDAP://CN=Administrator,CN=Users,DC=dc,DC=local”))
COM+ Security
217
CHAPTER 8

FIGURE 8.7
Set a reference to ActiveDS Type Library.

Once a connection is made, you can read properties in one of several different ways. Some
properties of the object can be read directly by using the dot operator. For example, the Class
property returns the type of the object. This property can tell you whether the object is a user,
group, or computer: 8

COM+ SECURITY
MsgBox objADSI.Name & “ is class “ & objADSI.Class

Most properties, however, must be returned through the use of the Get() or GetEx() method.
Both methods require you to specify a property name that you want to return. If you want to
return the first name, for example, you must specify the givenName property:
MsgBox objADSI.Get(“givenName”)

Along with the complexities of specifying the correct LDAP path, developers can often be
heard complaining about the cryptic naming of the properties. It’s hard to imagine how some-
one came up with givenName for the first name. Other properties are even worse. The last
name property is sn for surname. The city you live in is l for locale, and the country of origin
is c. Active Directory has a long list of available properties with no truly good reference.
However, you can use the Active Directory Schema explorer as a decent substitute for a com-
plete list of properties.
The Active Directory Schema explorer is an MMC snap-in that allows you to view and modify
the Active Directory Schema. Normally, this snap-in isn’t available because modifying the
Active Directory schema is a serious and dangerous undertaking. If you want to be able to
view the schema, you must register the dynamic link library schmmgmt.dll using REGSVR32.
The following code shows how to do this by using the command prompt in Windows:
REGSVR32.EXE SCHMMGMT.DLL
Business Services
218
PART III

CAUTION
Enabling the schema explorer might allow you to modify the Active Directory
schema. Improper modification of the schema can seriously impact Windows 2000.

Once the appropriate DLL is registered, you can add the Active Directory Schema snap-in to
the MMC through the Console menu. After you add the snap-in and run it, click the Attributes
folder to list all the available Active Directory properties. If your system has Microsoft
Exchange 2000 installed, your schema will have been extended already to include attributes
particular to Microsoft Exchange. Figure 8.8 shows the schema explorer.

FIGURE 8.8
Exploring the Active Directory schema reveals all available attributes.

Properties in the Active Directory come in two varieties: single-valued and multi-valued.
Single-valued properties return only one piece of data and can be retrieved easily through the
Get() method. Multi-valued properties, however, are returned as an array of elements with the
GetEx() method. Determining whether a property is single- or multi-valued can be done in the
Active Directory Schema explorer. Figure 8.9 shows a tabbed dialog with information for the
sn property.
COM+ Security
219
CHAPTER 8

FIGURE 8.9
The Active Directory schema shows single- and multi-valued properties.

When you use the GetEx() method to return a multi-valued property, you should receive the
data in a Variant and then determine how many elements are present in the array. I should note 8
here that GetEx() will also work for single-valued properties and will return an array with one

COM+ SECURITY
element. This makes GetEx() a more standard method for returning values than Get(). The
following code shows how to use GetEx() to return property values:
vData = objADSI.GetEx(“employeeID”)
For i = LBound(vData) To UBound(vData)
MsgBox vData(i)
Next

Along with reading properties, you might occasionally want to write properties back to Active
Directory. This is useful for times when a customer needs to change her address, for example.
Although we can write to Active Directory, you should remember that the database is opti-
mized for read access. Don’t simply use Active Directory as a substitute for SQL Server.
Writing to Active Directory is done with the Put and SetInfo methods. A write operation
requires two methods because Active Directory always uses a client-side data cache for proper-
ties to help speed the reading process. The Put method writes new values to the local cache,
and the SetInfo method updates Active Directory as a batch. The following code shows how
to set a property value with ADSI:
objADSI.Put “postalAddress”, “432 Washington Avenue”
objADSI.SetInfo

Just as in reading multi-valued properties, ADSI provides a separate method for writing multi-
valued properties. This is the PutEx method, which accepts an array of elements and allows
you to add the new values to the list or even overwrite all the values with your new set.
Business Services
220
PART III

Authenticating Users
In all the examples so far, we have connected to Active Directory without an apparent security
authentication. This is because the GetObject() function simply uses our own credentials to
access the directory. We have permission to read and write properties based on our network
login. This is a fine example of SSO at work.
However, sometimes we might want to connect to Active Directory by explicitly providing a
username and password. This might be because we’ve designated a single COM+ component
to be the proxy for all Active Directory services. It might also be because we are running an e-
commerce site where we allow anonymous access. If users access a Web site anonymously,
they have never really logged in to our system. They are seen generically as the anonymous
user account. In this case, we often use an HTML form to force a login and authenticate those
credentials with Active Directory.
Secure logins are accomplished by using the OpenDSObject method. This method allows you to
connect to an object in Active Directory by specifying a path along with a username and pass-
word. If the username and password are authenticated, a reference to the object is returned.
Accessing the OpenDSObject method requires you to first create a Namespace object, which
returns a reference to the root of the LDAP service. This connection is always made by using
GetObject(). The following code shows how to return a reference to the user John Q. Public
securely through the Administrator’s credentials:
Dim objNamespace As ActiveDs.IADsOpenDSObject
Dim objADSObject As ActiveDs.IADs
Dim strPath As String

StrPath = “LDAP://CN=John Q. Public,CN=Users,DC=dc,DC=local”


Set objNamespace = GetObject(“LDAP:”)
Set objADSObject = objNamespace.OpenDSObject _
(strPath, “Administrator”, “Password”, 1)

QUICK CHECK 8.1

Using ADSI
1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 08\Quick Check 8-1. This directory contains a project you can use
to access the Active Directory.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 8-1. Copy the contents from the CD-ROM directory into the new
directory you just created.
COM+ Security
221
CHAPTER 8

3. Open the project named adsixml.vbp. This project contains a class named Profile with
a single method named GetData. This method takes the username and password as an
input and returns the mailing address of the person who logged in.

NOTE
The LDAP paths created in the component are specific to the test layout used in cre-
ating the book. You will have to modify the path to get the project to work.

4. Compile the DLL. Create a new COM+ application named ADSI and install the com-
piled component. Be sure to enable the Auto Done feature for the GetData method.
5. Open the file client.hta. This page calls to the component and then displays the mail-
ing address information in the page. Figure 8.10 shows the results of the call for a given
user.

NOTE
8

COM+ SECURITY
You must enter values in Active Directory for any field you want to read. If a field
doesn’t have an assigned value, you will receive an error when you use the Get
method to view that field value.

FIGURE 8.10
Use this page to login to Active Directory.
Business Services
222
PART III

COM+ Security Features


COM+ supports two basic kinds of security for objects: declarative and programmatic.
Declarative security relies on the definition of roles within the Component Service explorer.
It’s largely a graphical system of managing permissions. Programmatic security, on the other
hand, relies on code within the business object to restrict access to components.

Declarative Security
Declarative security abstracts the security features of DCOM to provide a system that assigns
access permissions to Windows 2000 users and groups. Access permissions are assigned through
the definition of COM+ roles defined by the Component Services Administrator for the COM+
application. A role is a completely arbitrary name that represents a set of users and their permis-
sions. Creating a role is done by selecting the Roles folder underneath any COM+ application
and choosing New and then Role from the Action menu in the Component Services explorer.
Figure 8.11 shows the Component Services explorer prompting for the name of a new role.

FIGURE 8.11
Roles are arbitrary names that you provide to represent a set of users and permissions.

After a new role is created, you can assign Windows 2000 users to the role through the Users
folder. The Users folder is available for each role. Simply select the folder and choose New
and then User from the explorer’s Action menu. Component Services prompts you to choose
the individual or group to assign to the role. Figure 8.12 shows how you select Windows 2000
users for assignment to a role.
After users are assigned to roles, you must specify the permissions for a role. Each component,
interface, and method in a COM+ application has a tab on its property sheet named Security.
This tab contains all the roles in the application. To give permission for a role to access a com-
ponent, interface, or method, simply check the role on the Security tab (see Figure 8.13).
After you add the roles to the appropriate items, you must activate security for the application.
Security is activated using the Enable Authorization Checking option in the properties dialog
of the application. Figure 8.14 shows the Security tab for a COM+ application.
COM+ Security
223
CHAPTER 8

FIGURE 8.12
Windows 2000 users are assigned to roles within a package.

COM+ SECURITY
FIGURE 8.13
Use the Security tab to allow access by a specific role.

Programmatic Security
In addition to defining roles, COM+ also allows you to write code specifically designed to
enforce security within an object. When your object takes over the responsibility for managing
access to services, that’s called programmatic security. Although declarative security provides
a simple technique for securing an object, it might not be flexible enough for your needs. If
you want to obtain enhanced security information in code, you can access the
SecurityCallContext object through the object’s context.
Business Services
224
PART III

FIGURE 8.14
Use this dialog to enable security for an application.

The SecurityCallContext object has several methods that assist you in implementing pro-
grammatic security. The first is the IsSecurityEnabled method. This method tells you
whether security is enabled at the application level. Remember, enabling security at the appli-
cation level essentially prevents access checks at lower levels.
You can also use the SecurityCallContext object to identify the role of a particular caller in
your component. Your component can than take additional action to permit or deny functional-
ity. You can determine what role a user is by calling the IsCallerInRole method of the
SecurityCallContext. This method takes a String with the name of the role and returns a
Boolean value indicating True if the user is a member of the role. After you determine the role
membership, your object can manage the permissions inside the current user context.

QUICK CHECK 8.2

Determining Role Membership


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 08\Quick Check 8-2. This directory contains a project you can use
to determine role membership.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 8-2. Copy the contents from the CD-ROM directory into the new
directory you just created.
COM+ Security
225
CHAPTER 8

3. Open the project named programmatic.vbp. This project contains a single class named
Role with a method named WhatsMyRole. The method has no arguments because it
always checks the role for the current caller.
4. Compile the project into a DLL. Add this component to a new COM+ application named
Roles.
5. After you create the new application, open the Roles folder and select to create a new
role. Define a new role named Developer. This is the role that the component code
checks against.
6. Open the Users folder and add your account to the Developer role.
7. Open the properties for the Programmatic.Role component. On the Security tab, check
the Developer role to give it access to the component.
8. Locate the client.hta file. This page accesses the component when you run it and
returns a String indicating if you are in the Developer role. Run the page to view the
results. Figure 8.15 shows the page.

COM+ SECURITY
FIGURE 8.15
Use this page to check role membership.

In addition to checking the client’s role, COM+ also allows you to directly determine the client
identity. This is done through the SecurityCallContext object, which has a collection of
items used to return identification information:
• DirectCaller returns the identity of the current calling client.
• OriginalCaller returns the identity of the client that initiated the series of calls that
resulted in the current call.
Business Services
226
PART III

• You can even access information about every caller in the chain through the Callers
item. Direct callers will vary from original callers whenever you make a function call
between COM+ applications running under different identities.
Whenever you access information about callers to your components, it’s returned in the form
of a SecurityIdentity object. This object itself is a collection of information about the caller.
With this object you can access the AccountName, for example, to find the user’s identity.
Identifying the original caller is valuable in situations in which you want to know who is ulti-
mately making the request. You might, for example, want to log this information in the data-
base as an audit trail.

Conclusion
Determining the appropriate security strategy for your system depends on many factors. The
simplest way to implement security is to define roles. You also can define roles that correspond
directly to your defined domain groups. You can create, for example, an Administrator role and
assign the Domain Administrators as members. You can define a Guest role and assign Domain
Guests as members. This minimizes the overhead associated with role maintenance and cen-
tralizes access control.
If, however, you have many levels of security within an application, some combination of
declarative and programmatic security might be appropriate. Roles can be defined, whereas
business objects use IsCallerInRole to define finer grains of security control. The issue here,
of course, is that security is buried within the code and will require a recompile to change.
Also, some network administrators might be uncomfortable with the concept of software man-
aging security. In this case, programmatic security might be a tough sell.

EXERCISE 8.1

COM+ Security
COM+ applications require a combination of ADSI and Component Services to properly han-
dle security. In this example, you will create COM+ components that use role-based security to
grant access to methods. You will also use Active Directory in a new way to search for infor-
mation about users.
Creating the COM+ Components
Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
08\Exercise 8-1. This directory contains a partially completed project that you can use to
investigate security in COM+.
COM+ Security
227
CHAPTER 8

Step 2
On your hard drive, create a new directory in Windows Explorer named COM+\Exercise 8-1.
Copy the contents from the CD-ROM directory into this new directory you.

Step 3
Open the project named roledataserv.vbp. This project contains a class module named Books
for interacting with the pubs database, and a class module named Personal for retrieving
information from Active Directory.

Step 4
The Books class is already coded for you. It uses disconnected recordsets to return all the
books in the pubs database. Updates to the table are done through a batch update process.
Familiarize yourself with this code.

Step 5
Perhaps the most interesting aspect of this exercise is the Personal class, which uses the
SecurityCallContext object to retrieve the account name of the original caller and then
searches the Active Directory for the user object associated with that account. After the object
is located in the Active Directory, we use it to return the first name of the current user. 8

COM+ SECURITY
The Active Directory search is accomplished through the use of the OLEDB Provide for Active
Directory. This means that we can use ADO instead of ADSI to search the directory. Before we
search, begin by adding the code in Listing 8.1 to identify the original caller to the
GetFriendlyName method.

LISTING 8.1 Returning the Friendly Name


‘Get context object
Dim objContext As COMSVCSLib.ObjectContext
Set objContext = GetObjectContext()

‘Get the Security Call Context


Dim objSecurity As COMSVCSLib.SecurityCallContext
Set objSecurity = GetSecurityCallContext()

‘Find account for Original Caller


Dim objOriginal As COMSVCSLib.SecurityIdentity
Set objOriginal = objSecurity.Item(“OriginalCaller”)

‘Retrieve the full name for binding to Active Directory


Dim strAccount As String

strAccount = objOriginal.Item(“AccountName”)
strAccount = Right$(strAccount, Len(strAccount) - InStr(strAccount, “\”))
Business Services
228
PART III

Step 6
When you search Active Directory, you first make a connection using the OLEDB Provider
named ADsDSOObject. We use the ADO Connection object to accomplish the task. Add the fol-
lowing code below the code you added in step 5 to the GetFriendlyName method.
‘Connect to Active Directory
Dim objConnection As ADODB.Connection
Dim objRecordset As ADODB.Recordset
Dim strQuery As String

Set objConnection = New ADODB.Connection


objConnection.Provider = “ADsDSOObject”
objConnection.Open “Active Directory Provider”

Step 7
After connecting to Active Directory, you can create a query string to run. The syntax for
querying Active Directory is cryptic but looks somewhat like an LDAP string. Add the follow-
ing code under the code you added in step 6. This code will create a query that looks in Active
Directory for the object associated with the original caller.
strQuery = “<LDAP://dc=dc,dc=local>;”
strQuery = strQuery & “(&(objectCategory=person)(sAMAccountName=” _
& strAccount & “));givenName;subtree”

Set objRecordset = objConnection.Execute(strQuery)

‘Return First name


Dim strName As String
strName = objRecordset.Fields(0).Value
GetFriendlyName = strName

Step 8
Compile the code into an ActiveX DLL. Create a new COM+ application named Security and
place both class modules in the application.
Configuring Security
Step 9
In the Component Services explorer, create two roles for the new COM+ application. Name the
new roles Administrator and Guest. Add new users to each role. Figure 8.16 shows the roles
and users in the explorer.

Step 10
Once the roles are created, enable access checks for the entire application on the Security tab.
Then open the property sheet for the Personal class. Figure 8.17 shows the property sheet for
the COM+ application.
COM+ Security
229
CHAPTER 8

8
FIGURE 8.16

COM+ SECURITY
Create roles for the components.

FIGURE 8.17
Enforce access checks for the application.

Step 11
Right-click the Personal class and open the property dialog. On the Security tab, check both
the Guest and Administrator roles to allow access by both roles to this class.
Business Services
230
PART III

Step 12
Under the Books class, locate the GetData and Update methods. Open the property sheet for
each method. Allow the Administrator role to access either method, but only allow the Guest
access to the GetData method. This will prevent guests from calling this method to modify
data.
Testing the Application
Step 13
Locate the front-end file default.hta. This page reads the data from the database and displays
it in a grid. You can modify the data in the grid, but only Administrators can update the data-
base. Run the application under different credentials to see the results. Figure 8.18 shows the
page.

FIGURE 8.18
Try the application as an Administrator and a Guest.
COM+ Business Features CHAPTER

9
IN THIS CHAPTER
• The COM+ Event System 232

• COM+ Constructors 238

• Compensating Resource Manager


System 242
Business Services
232
PART III

Developers who have previously written applications for the Microsoft Transaction Server
(MTS) typically find that the move to COM+ is straightforward. After all, the fundamental
COM+ principles of resource management and transaction control remain true to their MTS
roots. Furthermore, the Visual Basic 6.0 threading model prohibits the use of several new
COM+ features, which all serve to make COM+ programming familiar. This might lead some
of you to wrongly believe that there are no truly new features in COM+ for the VB developer.
This chapter examines three new features of COM+ that have no predecessor in MTS:
• The COM+ event system allows you to create event-driven systems in which one COM+
component can send events to another across applications.
• The new COM+ constructor allows you to control the way an object behaves at activa-
tion through the use of a command String.
• You can use COM+ to manage transactions where you might not expect to see them—
such as in flat-file access—through the new Compensating Resource Manager feature.

The COM+ Event System


All Visual Basic programmers are familiar with the concept of an event because events perme-
ate every aspect of Visual Basic development. Not even a simple program is accomplished
without using them.
Visual Basic events, such as Form Load, are said to be early bound or tightly bound because
they require a direct knowledge of the available events and their function signature directly in
code. For example, if you want to receive the MouseDown event, you must write the code for the
event directly in the form where the event fires. No other part of your application is generally
capable of receiving that event.
Beginning with Visual Basic 5.0, Microsoft extended the event system to include the ability to
generate your own events from class modules. Therefore, you can define an event signature
and then raise the event programmatically. Although this system improved Visual Basic’s over-
all event capabilities, it was still a tightly bound system. To receive the events, an object vari-
able had to be declared WithEvents, which then tightly bound the event provider and event
consumer. Furthermore, Visual Basic events don’t work well in a distributed system in which
events must cross processes and possibly fire on several different machines.
The COM+ event system introduces Visual Basic programmers to the concept of a loosely cou-
pled event (LCE) system in which event consumers—known as subscribers—don’t have to
declare a variable against the event provider—known as a publisher. Instead, the subscriber
and publisher both rely on an interface definition in the form of a COM+ event class. Figure
9.1 shows a conceptual drawing of the COM+ event system.
COM+ Business Features
233
CHAPTER 9

COM+ Subscriber
Event System

Publisher Event Class Subscriber

Subscriber

FIGURE 9.1
COM+ events loosely couple publisher and subscriber.

Event Classes
Understanding the COM+ events system begins by understanding COM+ event classes. Event
classes form the primary mechanism for decoupling the event as they define the interface that
the Publisher calls and the subscriber implements. Neither Publisher nor Subscriber is required
to have any knowledge of the other because they operate through the event class.
You define an event class in Visual Basic as you would any other interface—by simply defin-
ing the function signature for the events you want to fire. In fact, event classes are nothing
more than interfaces built into an abstract class.
Suppose that you wanted to provide an email notification feature for an online store. In this
scenario, you can imagine that products are ordered online and then processed offline with a
post-shipping customer notification and a tracking number.
To define the event class, you start a new ActiveX DLL project in Visual Basic to create the
new function signature inside an abstract class. For the sake of argument, say that the name of
the class is ISendMail. The abstract class will define a single method named Process. The
following shows the function signature for the interface: 9

COM+ BUSINESS
Public Sub Process( _

FEATURES
ByVal strProductID As String, _
ByVal strDescription As String, _
ByVal strEMail As String, _
ByVal strTracking As String)

End Sub

Though your interface is admittedly simple, you can include any further information you want.
However, remember a few points concerning the interface definition:
• Your interface can’t have a return value. Because LCE systems decouple the Publisher
and the Subscriber, there’s no way to return data to the event’s Publisher, meaning that
you must declare your interface as a Sub and not a Function.
Business Services
234
PART III

• You must declare all variables in the interface by value for the same reason that you can’t
use a Function. By-reference variables are returned to the caller after the routine is
processed, which is impossible in a LCE system.

Key Principle
Declare event class interfaces with the Sub keyword. Declare all interface arguments
with the ByVal keyword.

When the interface is properly defined, you are ready to install it in a COM+ application.
Because COM+ manages the event system for you, you must specifically install the interface
as an event class. COM+ allows you to do this through the COM Component Install Wizard
shown in Figure 9.2.

FIGURE 9.2
Use the COM Component Install Wizard to install the event class.

Event Subscribers
When the event class is installed, you need to create a Subscriber to receive the new event and
implement the interface defined by the event class. In this implementation, the Subscriber
defines the actions for the event. In this case, you use the Collaborative Data Objects (CDO) to
send the mail. Listing 9.1 shows how the Subscriber implements the interface defined by the
event class.
COM+ Business Features
235
CHAPTER 9

LISTING 9.1 Subscriber Implementation


Implements ISendMail

Private Sub ISendMail_Process( _


ByVal strProductID As String, _
ByVal strDescription As String, _
ByVal strEMail As String, _
ByVal strTracking As String)

‘Author: Scot P. Hillier


‘Purpose: Send E-Mail
‘Revisions: 5/9/00 Original

Dim objMail As CDONTS.NewMail


Set objMail = New CDONTS.NewMail
objMail.From = “sales@xyz.com”
objMail.To = strEMail
objMail.Subject = “Order Update”
objMail.Body = “Product “ & strProductID & “: “ _
& strDescription & “ shipped under tracking number “ _
& strTracking
objMail.Send

End Sub

After you implement the interface, the Subscriber must be placed in a COM+ application by
using the Component Install Wizard. However, after the component is installed, you must
establish the subscription with the COM+ event system.
Each component in a COM+ application has a Subscriptions folder beneath it that contains 9
information about all events that your component will receive. To create a new subscription,

COM+ BUSINESS
select the folder and choose New and then Subscription from the Action menu to start the New

FEATURES
Subscription Wizard. First, you will have to select the method that will receive events as shown
in Figure 9.3. For this example, the method is Process.
When the method name is selected, Component Services prompts you to identify the event
class associated with that interface. Because your event system might have several event
classes that define an interface compatible with your Subscriber, COM+ needs to know specifi-
cally which one to associate with the subscription. Figure 9.4 shows how to select the event
class in the wizard.
Business Services
236
PART III

FIGURE 9.3
Select the method to receive the event.

FIGURE 9.4
Select the event class to associate with the subscription.

Finally, COM+ will prompt you to provide a name for the new subscription and give you a
chance to enable the subscription and allow your Subscriber to receive events immediately.
Otherwise, you can use the COM+ Catalog Administration objects to enable the subscription.
(These objects are covered in detail in Chapter 15, “COM+ Catalog Administration.”) Figure
9.5 shows the final settings for the subscription.
After running the wizard, you will see a new entry in the Subscriptions folder indicating that
the Subscriber is ready to receive events from the COM+ event system. The only thing left to
do is create a Publisher.
COM+ Business Features
237
CHAPTER 9

FIGURE 9.5
Name the subscription and enable event notification.

Event Publishers
Event Publishers are COM+ components that fire events in the form defined by an event class.
Creating a Publisher is relatively simple after the event class and Subscriber are defined. To
fire an event, the Publisher simply creates an instance of the event class and calls the exposed
method. The following code shows how this might happen:
Dim objEvent As OrderSystem.ISendMail
Set objEvent = New OrderSystem.ISendMail
objEvent.Process “1111”, “Floppy Disks”, _
“Scot_Hillier@hotmail.com”, “ABC123”

Notice how the Publisher declares and creates an instance of the event class itself. Normally,
creating an instance of an interface will accomplish nothing because the interface has no code. 9
However, COM+ uses this mechanism to decouple the Publisher and Subscriber. When the

COM+ BUSINESS
Publisher calls the Process method, an event is broadcast throughout the COM+ event system.

FEATURES
Thus, any component with an active subscription to this event will receive notification.
The LCE system used by COM+ has several advantages beyond simply decoupling the
Publisher and Subscriber. Because of the nature of the system, the number of subscribers can
change at any time without changing the code in the Publisher. If, for example, you also want
to provide shipment notification to the marketing department, the same event can trigger an
email message to that department. Furthermore, you can easily enable or disable any combina-
tion of subscriptions by using the subscription’s property sheet.
Business Services
238
PART III

Filtering Events
Whenever you define multiple subscriptions for a single event class, you will want to control
the conditions under which an event is fired. For example, you might want to send specific
shipment notifications to various departments concerning their particular products. In other
words, the toy department doesn’t want to know when shoes are shipped. The process of
restricting events within a subscription is known as event filtering.
COM+ provides a simple mechanism for filtering events at the subscription level. Filters are
established through the subscription property sheet in the Options tab. Here you will find a
Filter Criteria text box that enables you to specify a Boolean criteria associated with any para-
meter in the interface. You construct the filter by naming the parameter followed by a Boolean
expression using symbols such as =, <, and >, as well as operators such as AND, OR, and NOT.
Figure 9.6 shows a typical filter.

FIGURE 9.6
Filter events using Boolean expressions.

COM+ Constructors
The management of connection strings has always plagued MTS developers. The alternatives
to placing connection strings directly in code were never sufficient, and that route is still taken
more often than not. Universal Data Link (UDL) files require a disk hit to Read. Using the
Shared Property Manager (SPM) saves the disk hit, but the SPM works only when it resides in
the same application as the calling client. All in all, there’s never been a good way to manage
these strings—until now.
COM+ Business Features
239
CHAPTER 9

COM+ introduces a simple yet useful idea known as a constructor. Truthfully, the idea of a
constructor isn’t new, but its appearance in COM+ certainly is. A constructor is simply a string
specified in the property sheet of a component and then passed into the component when it’s
activated. In this way, you can move database connection strings and other meta data out of
your code and into the property sheet where it can easily be maintained. Furthermore, the
COM+ constructor is far more efficient than other techniques that require a disk hit. Figure 9.7
shows a database connection string defined for a component on the Activation tab.

FIGURE 9.7
Constructors are passed to the component when it’s activated.

After the constructor is defined, it’s accessed through a special interface implemented by the
component. The special interface, called IObjectConstruct, defines one method named
9
Construct. COM+ calls this method each time your object is activated. The method passes in a

COM+ BUSINESS
reference to an IObjectConstructString object that you can use to access the construction

FEATURES
string. The following code shows how to implement the interface in your component:
Implements COMSVCSLib.IObjectConstruct

Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object)

End Sub

Reading the ConstructString property of the IObjectConstructString object returns the


construction string. After the construction string is read, you should store it in a module-level
variable within the component. Though it might seem that way, storing the construction string
at the module level doesn’t violate the principle of stateless components. This is because the
Business Services
240
PART III

construct string is passed in when the object is activated, thus preserving the module-level vari-
able until the completion of a function that deactivates the object. The basic code for
preserving the construct string is as follows:
Implements COMSVCSLib.IObjectConstruct
Private m_Connect As String

Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object)

m_Connect = pCtorObj.ConstructString

End Sub

QUICK CHECK 9.1

Constructors
1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 09\Quick Check 9-1. This directory contains a project you can use
to investigate constructors.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 9-1. Copy the contents from the CD-ROM directory into this new
directory.
3. Open the project named construction.vbp. This project contains a class named
DataClass with a single method named GetTitles. This method uses the construction
string to connect to the pubs database. The code to retrieve the construction string is
already done for you.
4. Compile the project into an ActiveX DLL. Install the component into a new COM+
application named Constructors.
5. After the component is installed in the new COM+ application, open the property sheet
for the component. On the Activation tab, enable object construction and type an appro-
priate connection string for the pubs database into the text box (for example,
Provider=SQLOLEDB;Data Source=(local);Initial Catalog=pubs;UID=sa;PWD=;).

6. The COM+ component is accessed through an Active Server Page. Therefore, you will
have to share your directory on the Web. Right-click the project folder in the file
explorer and select Sharing. Establish a new Web share named Construction as shown
in Figure 9.8.
COM+ Business Features
241
CHAPTER 9

FIGURE 9.8
Share your project folder to access the Active Server Page.

7. In the Internet Explorer, navigate to the URL associated with the shared folder. The
Active Server Page calls the COM+ component and formats the return XML string using
an XSL style sheet. Figure 9.9 shows the final results.

COM+ BUSINESS
FEATURES

FIGURE 9.9
All titles are returned and displayed in a table.
Business Services
242
PART III

Compensating Resource Manager System


COM+ provides an excellent mechanism for dealing with database transactions through the
Microsoft Distributed Transaction Coordinator (MSDTC). As discussed in Chapter 7, “COM+
Transactions,” the transaction attributes of your COM+ components affect how MSDTC
behaves and allows for voting in database transactions. Often, however, developers wish that
they had access to MSDTC’s two-phase commit capabilities for operations other than database
writes. COM+’s Compensating Resource Manager (CRM) system provides this exact mecha-
nism.
In the past, if you wanted two-phase commit capabilities for non-database transactions, you
had to write a resource manager specifically for the desired resource. The problem is that there
were no tools to assist in this development. CRM is an alternative to creating a full-blown
resource manager, and the best part is that it can easily be created in Visual Basic.
CRM is implemented as two separate COM+ components: the CRM Worker and the CRM
itself. Normally the CRM Worker is used by some component in the system that wants to per-
form transactional work. For example, if you had a business component that wanted to write
data to a flat file under a transaction, it would first create an instance of the CRM Worker.
Most often, the CRM Worker is analogous to a data component.
CRM Workers join in a transaction begun by the business component. To guarantee adherence
to the ACID properties, the CRM Worker must write its actions out to a durable log. A
CRMClerk object, accessible through the COM+ Services library, provides access to the durable
log. As the CRM Worker performs operations, it records the actions for rollback in case of a
failure. After the transaction is completed and all participating components have voted, COM+
creates an instance of the CRM and begins to play the log back. For each action, the CRM is
directed to commit or abort the action based on the transactional voting accumulated by
MSDTC. The CRM can then take any action required to commit or abort the transaction.
Figure 9.10 shows a conceptual drawing of the CRM system.

CRM Workers
Creating your own CRM begins with the CRM Worker. Again, the CRM Worker should really
be thought of as a data component that writes all its actions to a durable log. The log’s purpose
is to survive a possible mid-transaction system failure. Because the CRM Worker is a data
component that participates in the transaction, it should have its transactional attribute set to
Required. The business component will initiate and control the transaction, so it will have a
transactional attribute set to Requires New.
COM+ Business Features
243
CHAPTER 9

3. The Data Component performs actions on


the non-transactional resource and records Non-Transactional
all the actions in the durable log. Resource

Business CRM Worker


Component (Data
Component)

1. The Business
Component begins a
new transaction. CRMClerk CRM Worker
object (Data
2. The Data Component Component)
creates a CRMClerk object
to access the durable log.
4. After all components finish their work and
vote in the transaction, the CRM is
Log automatically created. Each action is played
back from the log. The CRM takes any
action required to commit or abort the actions
based on the vote tally.

FIGURE 9.10
The CRM system allows transactional operations on any resource.

Key Principle
The business component must be set to require a new transaction, whereas the CRM
Worker must be set to require a transaction.

You design the CRM Worker exactly as you would any data component. The only modification
is that the component must create an instance of the CRMClerk object so that it can access the
9

COM+ BUSINESS
durable log. CRMClerk should be declared as a local variable within the method of the CRM

FEATURES
Worker just like any other variable in COM+. The following code shows how to create the
CRMClerk object:

Dim objClerk As COMSVCSLib.CRMClerk


Set objClerk = New COMSVCSLib.CRMClerk

CRM Clerks
The CRMClerk object is the primary interface to the CRM system and is used solely by the
CRM Worker to control the transaction. The first operation the CRM Worker must perform is
notifying the CRMClerk which CRM will be created after transaction voting is complete. This is
Business Services
244
PART III

accomplished through the RegisterCompensator method. I discuss creating the CRM in the
next section, but the following code shows how a CRM might be registered with the CRMClerk:
objClerk.RegisterCompensator _
“CRMXML.Compensator”, “Test Compensator”, 7

The RegisterCompensator method accepts the Programmatic Identifier (ProgID) of the com-
ponent that will act as the CRM. The second argument is a description for the CRM that can be
viewed from any available monitoring tools. The third argument is used to determine what
notifications are sent to the CRM after the transaction completes according to the information
in Table 9.1.

TABLE 9.1 CRM Flags


Value Meaning
1 Receive Prepare phase messages
2 Receive Commit phase messages
4 Receive Abort phase messages
7 Receive all messages
16 Fail in-doubt transactions

After the CRM is registered, the CRM Worker can begin to perform operations on the
resource. Before performing any operation, the CRM Worker makes an entry in the durable log
before the operation is performed in case a system failure occurs during the operation. This is
called a write-ahead operation.
The CRM Worker is responsible for determining the exact format of the log entry. When using
a CRM from Visual basic, log entries are made as a Variant array. The CRM Worker can put
any information it wants into the Variant array; however, this format must be known by the
CRM, so the log entries can be read after the transaction is complete. Log entries are written
using the CRMClerk object’s WriteLogRecordVariants method which takes a single Variant
array as an argument. The following code shows how a log record might be written:
vData = Array(“Operation #1”, “Add 1000”,”Account #42”)
objClerk.WriteLogRecordVariants vData

Log records aren’t durable by default, so if you want to ensure that log records survive a sys-
tem crash, follow each write operation with a call to the ForceLog method. This will flush the
record from the cache and write it out to a hard log. Durable logs are written out to the
winnt\system32\dtclog directory with a .CRMLOG extension.
COM+ Business Features
245
CHAPTER 9

Compensating Resource Managers


CRM Workers and the calling business component should all vote for the success or failure of
the transaction using the SetComplete or SetAbort method. After the voting is complete, the
CRM system will create an instance of the component identified in the RegisterCompensator
method. You create your own CRM by defining a COM+ component that implements the
ICrmCompensatorVariants interface, which is available directly from the COM+ Services
library.
The ICrmCompensatorVariants interface contains a number of methods that you must imple-
ment correctly to commit or abort transactions. The CRM conforms to the ACID properties for
transactions through the use of two-phase commit. This means that your CRM must handle a
prepare phase, commit phase, and abort phase. Table 9.2 lists the methods contained in the
ICrmCompensatorVariants interface.

TABLE 9.2 ICrmCompensatorVariants Methods

Method Description
SetLogControlVariants Gives CRM access to the durable log to write new records if
required
BeginPrepareVariants Marks the beginning of the Prepare phase
PrepareRecordVariants Called to prepare each log record
EndPrepareVariants Marks the end of the Prepare phase
BeginCommitVariants Marks the beginning of the Commit phase
CommitRecordVariants Called for each log record to commit
EndCommitVariants Marks the end of the Commit phase
BeginAbortVariants Marks the beginning of the Abort phase 9

COM+ BUSINESS
AbortRecordVariants Called for each log record to abort

FEATURES
EndAbortVariants Marks the end of the Abort phase

After the CRM is instantiated, the SetLogControlVariants method is called first to give the
CRM access to the CRMClerk object. This allows the CRM to write new records to the log, if
required. The SetLogControlVariants method is called one time before each phase of the
transaction.
The Prepare phase begins the transaction when the BeginPrepareVariants method is called.
Next, each record in the log is passed to the CRM for preparation via the
PrepareRecordVariants method. This method provides the record in the same format as the
CRM Worker wrote it and is delivered as a Variant array. During preparation, the CRM can
Business Services
246
PART III

choose to ignore any log record by returning True from the PrepareRecordVariants method.
The Prepare phase concludes with a call to the EndPrepareVariants method.
After preparation, each record is sent to the CRM for committing or aborting based on the vote
tally accumulated by MSDTC. If a record is to be committed, the Commit phase begins with a
call to the BeginCommitVariants method. Each record to be committed is then sent to the
CommitRecordVariants method. The Commit phase ends when the EndCommitVariants
method is called.
If a transaction is to be rolled back, the Abort phase is executed. The Abort phase is similar to
the Commit phase. The phase begins with a call to the BeginAbortVariants method. Each
record to rollback is then sent to the AbortRecordVariants method. Finally, the phase ends
with a call to the EndAbortVariants method.
Although the CRM system guarantees that the records in the durable log will be seen by the
CRM, there’s no guarantee that the CRM will take appropriate action. You must decide what
actions are necessary in each of the transaction’s three phases. The CRM you design must per-
form the specific operations necessary to commit or rollback the work represented by the log
entries.
After you construct your CRM, you need to install it in a COM+ application in the normal
fashion. However, the CRM won’t be invoked unless you specifically enable the CRM system
for your application on the Advanced tab of the property sheet as shown in Figure 9.11.

FIGURE 9.11
The CRM system must be enabled for your application.
COM+ Business Features
247
CHAPTER 9

QUICK CHECK 9.2

Compensating Resource Managers


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 09\Quick Check 9-2. This directory contains a project that you
can use to build a CRM.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 9-2. Copy the contents from the CD-ROM directory into this new
directory.
3. Open the project named crm.vbg. This project group contains three ActiveX DLL pro-
jects:
• Crmbiz.vbp is the business layer. It contains a single class named Transactor.
• Crmdata.vbp is the data layer. It contains the CRM Worker as a class named
Worker. It also contains a class to read data named Reader.
• Crmxml.vbp is the Compensating Resource Manager.
This exercise establishes transactional updates for an XML file acting as a database.
4. Select the Transactor class in the Project Explorer. Notice that this class has its
MTSTransactionMode property set to 4-RequiresNewTransaction. Remember that even
when using a CRM, the business layer initiates and controls the transaction.
5. Select the Worker class. This class has its MTSTransactionMode property set to
2-RequiresTransaction. Remember that the CRM Worker must participate in the trans-
action started by the business layer.
9
6. Open the code module for the Worker class. You will find a single method named

COM+ BUSINESS
AdjustBalance. This example is similar to the simulated bank transfer example in

FEATURES
Chapter 7. The difference here is that you use the XML file like a database instead of
SQL Server. Listing 9.2 shows the code used to register the CRM and write ahead to the
durable log.

LISTING 9.2 Registering the CRM


‘Create a new CRMClerk
Dim objClerk As COMSVCSLib.CRMClerk
Set objClerk = New COMSVCSLib.CRMClerk

‘Register our CRMCompensator


objClerk.RegisterCompensator “CRMXML.Compensator”, “Test Compensator”, 7
Business Services
248
PART III

LISTING 9.2 Continued


‘Write data ahead to log
Dim vData
vData = Array(strAccountID, curAmount)
objClerk.WriteLogRecordVariants vData
objClerk.ForceLog

7. After the log record is written, the Worker class accesses the XML file as a standalone
recordset and performs a write. This happens for each half of the money transfer. The
code in Listing 9.3 shows how the XML file is accessed.

LISTING 9.3 Accessing the XML File


‘Update account balance
Set objRecordset = New ADODB.Recordset
objRecordset.CursorLocation = adUseClient
objRecordset.CursorType = adOpenStatic
objRecordset.LockType = adLockBatchOptimistic
objRecordset.Open App.Path & “\accounts.xml”, _
“Provider=MSPersist”

Do While Not objRecordset.EOF


If objRecordset!AccountID = strAccountID Then
objRecordset.Fields(“AccountBalance”).Value = _
objRecordset.Fields(“AccountBalance”).Value + curAmount
objRecordset.Update
blnCommit = True
Exit Do
End If
objRecordset.MoveNext
Loop

objRecordset.Save App.Path & “\accounts.xml”, adPersistXML

8. Select the Compensator class to implement the ICrmCompensatorVariants interface.


Most of the methods aren’t used, but you do take action if directed to abort the transac-
tion. If the transaction is to be aborted, the log record will contain the account number
and amount to roll back. The following code fragment shows how the rollback is applied:
objRecordset.Fields(“AccountBalance”).Value = _
objRecordset.Fields(“AccountBalance”).Value - _
CCur(pLogRecord(rsAmount))
COM+ Business Features
249
CHAPTER 9

9. Compile the project group into three separate ActiveX DLLs. Compile the projects in
this order: Crmdata.vbp, Crmbiz.vbp, and then Crmxml.vbp. Add all the components
to a new COM+ application named CRM.
10. In the property sheet for the new COM+ application, enable the Compensating Resource
Manager by using the check box found on the Advanced tab.
11. Locate the file client.hta. This page is used to test the CRM. Double-click the file to
run the application. Transfer money between two accounts. Now try using a bad account
number and prove that the transaction is rolled back.

CRM Issues
When designing a CRM, you should keep several issues in mind. Remember that you are
assuming full responsibility for correctly implementing transaction behavior based on the log
records. Following is a list of items to consider.

Isolation
The CRM must be designed to handle multiple clients performing multiple transactions. Your
design must adequately isolate the transactions so that they perform independently. Carefully
consider the format and types of data in each log record.

Recovery
After a system crash, the CRM will execute a recovery attempt when it’s started. However,
COM+ won’t automatically start an application, so you must design a mechanism to start the
CRM application when recovering. This can be done with a bootstrap program or manually
from the Component Services explorer.
During recovery, a CRM Worker will be unable to register a CRM with the CRMClerk object. 9

COM+ BUSINESS
Attempting to register a CRM that’s in recovery will result in a Recovery in Progress error.

FEATURES
If this error is received, the CRM Worker should wait and attempt registration again before
proceeding.

Duplicate Log Records


It’s possible for the CRM to receive duplicate log records that might direct the same commit or
abort action that was already taken. The CRM must be able to identify and handle these
records. Often this means simply ignoring error messages that occur when the second opera-
tion is performed.
Business Services
250
PART III

EXERCISE 9.1

A System Error Log


This exercise uses the COM+ event system and a construction string to create a system-wide
error log. This technique allows you to create a single error log for an entire distributed system,
which allows all components to report their runtime errors in a centralized location. I find this
type of log invaluable for debugging.
Creating the COM+ Components
Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
09\Exercise 9-1. This directory contains a partially completed project that you can use to
investigate events and constructors in COM+.

Step 2
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
9-1. Copy the contents from the CD-ROM directory into this new directory.

Step 3
Open the project group events.vbg. In this group you will find three ActiveX DLLs:
events.vbp, publisher.vbp, and subscriber.vbp.

Step 4
Examine the ILogErrors interface. This interface functions as the event class for our system
log. The Logger class in the subscriber.vbp project implements this interface.

Step 5
Open the code for the DataClass class in publisher.vbp. This class creates an instance of
ILogErrors and uses it to report runtime errors. The following code is contained in the error
handler for the class, and can easily be added to every component in a large system:
‘Log the Error
Set objLog = New Events.ILogErrors
lngNumber = Err.Number
strDescription = Err.Description
strModule = “DataClass”
strProcedure = “GetData”
objLog.LogError lngNumber, strDescription, strModule, strProcedure
COM+ Business Features
251
CHAPTER 9

Step 6
Compile the project group into three ActiveX DLLs. Compile the projects in this order:
events.vbp, publisher.vbp, and then subscriber.vbp. Create a new COM+ application
named Error System, but don’t install any of the components yet.
Installing the COM+ Components
Step 7
Begin by installing the events.dll into the new COM+ application. This component is an event
class, so be sure to select Install new event class(es) from the Component Install Wizard.

Step 8
After the event class is installed, use the Component Install Wizard to install both sub-
scriber.dll and publisher.dll into the COM+ application.

Step 9
Locate the Subscriber component under the Components folder of the new COM+ applica-
tion. Open the Subscriptions folder for the component and select to add a new subscription.
Using the wizard, add a new subscription for the LogError method and enable the subscription
immediately. Figure 9.12 shows the new subscription in the Component Services explorer.

COM+ BUSINESS
FEATURES

FIGURE 9.12
Add a new subscription to receive system errors.
Business Services
252
PART III

Step 10
Using the property sheet for the Publisher component, specify a construction string in the
Activation tab. This string should be a valid database connection string for your system to
access the SQL Server pubs database (for example, Provider=SQLOLEDB;Data
Source=(local);Initial Catalog=pubs;UID=sa;PWD=;).

Using the COM+ Components


Step 11
This example uses an Active Server Page to access the COM+ components. Therefore, you will
have to share the project directory on the Web. In the file explorer, right-click the project direc-
tory and select to share the directory. Share the directory on the Web as ErrorSystem.

Step 12
Open the file results.asp. This page calls the Publisher and receives the resulting recordset as
XML. Add the following code to the ASP page to produce the recordset:
Dim objData
Set objData = Server.CreateObject(“Publisher.DataClass”)
Response.Write objData.GetData(Request.Form(“txtSearch”))

Step 13
Start the Internet Explorer and navigate the URL you established when you shared the project
directory. The default page for the Web share will invite you to enter a partial search string. It
will then return the results as XML formatted with XSL as shown in Figure 9.13.

Step 14
You can generate a system error to test the log file by deleting your construction string from
the Publisher. This will generate a runtime error when a database connection is attempted. You
can view the error by opening the file’s error.log
COM+ Business Features
253
CHAPTER 9

FIGURE 9.13
Search for records using the Web pages.

COM+ BUSINESS
FEATURES
Asynchronous COM+ CHAPTER

10
Applications

IN THIS CHAPTER
• The Microsoft Message Queue 256

• MSMQ Applications 258

• Queued Components 265


Business Services
256
PART III

Throughout the book so far, we’ve designed and implemented components that worked syn-
chronously within COM+ systems. This means that every time a method is called, the system
waited for the method to process before control was returned to the client. Although you can
build many COM+ applications successfully this way, distributed applications increasingly rely
on asynchronous processing.
Asynchronous processing allows you to invoke a method call on a component and then imme-
diately return control to the calling client. The advantage of this design is that the client isn’t
delayed while the system processes the request. To the user, the system seems to respond much
more quickly than it actually does. In some cases, asynchronous processing is required just to
make the system work at all. This often happens when transactions are initiated through a
browser interface. I’ve seen many synchronous systems that worked well on the developer’s
desktop fail miserably in production because the ASP script engine kept timing out before the
COM+ component completed the transaction.
In this chapter, we will investigate asynchronous COM+ components. When we create these
components, we will have two options to choose from: using the Microsoft Message Queue
(MSMQ) directly or developing a queued component (QC). MSMQ solutions give us a high
degree of control over processing, whereas QC solutions are actually a specific category of
MSMQ solution that makes it easier to develop asynchronous components.

The Microsoft Message Queue


MSMQ is a store-and-forward service that enables distributed objects to communicate asyn-
chronously either by design or because of a failure. Adding MSMQ to your architecture can
significantly improve the overall reliability of your system. MSMQ uses a system of queues to
support asynchronous messaging. These queues act as storage areas for messages that can con-
sist of either text or binary information. Messages can be delivered to a queue by one distrib-
uted object and retrieved later by a different object. Messages can be as simple as plain text or
as complex as a COM object.
Although the overall concepts of message queuing are fairly straightforward, organizations that
want to employ MSMQ technology should plan carefully to avoid problems. Chief among your
planning concerns should be how many MSMQ installations you need, where they will be
located, and how the installations will interact to achieve the design goals for an application.
Unlike many services you use with distributed applications, any application using message
queuing is likely to employ several servers running MSMQ. An enterprise installation of
MSMQ consists of a series of servers having relationships to each other. MSMQ servers are
typically installed to connect outbound offices to the main network as well as to route mes-
sages within a local area network (LAN).
Asynchronous COM+ Applications
257
CHAPTER 10

In MSMQ terminology, a domain environment is a network with one or many servers running
Active Directory. This might consist of a single LAN or a global network of separate domains
defining a forest. In any case, each domain consists of an installation of MSMQ. MSMQ
installations use the Active Directory to publish information about available queues in the
domain environment.
A domain environment is divided into many sites. Sites represent physically distinct portions
of the network such as an outbound office connected by a phone line. Domains, on the other
hand, represent the logical structure of the network. Sites generally consist of a set of comput-
ers all running the same protocol and a server running Active Directory.
After you establish the queuing architecture for your enterprise, you have to create and manage
queues for the enterprise. Creating a queue can be done for any MSMQ installation through
the Message Queuing explorer located in the Computer Management explorer (see Figure
10.1). Simply right-click the folder where you want to create the new queue and select New
and then Queue from the pop-up menu. You will then be prompted to name the queue and indi-
cate whether you want the queue to support transactions. When the queue is created, you can
examine its properties by right-clicking it and selecting Properties. The Message Queuing
explorer responds by showing a tabbed Queue Properties dialog where you can set several key
attributes for the queue.

FIGURE 10.1
The Message Queuing explorer is used to administer message queues.
10
ASYNCHRONOUS
APPLICATIONS
COM+
Business Services
258
PART III

MSMQ Applications
Programming applications to use MSMQ is done through the MSMQ Object Model. The
model allows you to programmatically manage queues and messages. You can create, locate,
and delete queues as well as send and receive messages. You can programmatically control
MSMQ directly from an application or as a function of a business object running under COM+
control. Figure 10.2 shows the MSMQ object model.

MSMQApplication

MSMQQuery

MSMQQueueInfos

MSMQQueueInfo

MSMQQueue

MSMQEvent

MSMQMessage

MSMQTransactionDispenser

MSMQTransaction

MSMQCoordinatedTransactionDispenser

MSMQTransaction

FIGURE 10.2
MSMQ applications are created using the MSMQ object model.

MSMQApplication Object
The MSMQApplication object contains properties and methods for obtaining information
about the server running MSMQ. The method named MachineIdOfMachineName is used to
return the GUID for an MSMQ server:
MachineID = MSMQApplication. MachineIdOfMachineName(“machinename”)

This allows you to locate a server by name and then subsequently locate queues on that server.
Asynchronous COM+ Applications
259
CHAPTER 10

MSMQQuery Object
The MSMQQuery object locates queues in the domain environment. By using this object, your
application can find the proper queue for sending a message. The MSMQQuery object has
only a single method, the LookUpQueue method, which accepts a number of optional arguments
that allow you to search for queues based on known characteristics. When a queue or queues
are located that match the criteria, they are returned through an MSMQQueuesInfo object. The
following is the syntax for locating a queue with the LookUpQueue:
Set MSMQQueuesInfo = MSMQQuery.LookupQueue _
([QueueGuid][, ServiceTypeGuid][, Label][, _
CreateTime][, ModifyTime][, RelServiceType][, _
RelLabel][, RelCreateTime][, RelModifyTime])

In this syntax,
• QueueGuid is a globally unique identifier (GUID) that uniquely identifies a queue.
• ServiceTypeGuid is a GUID that identifies a family of queues. If you search for queues
based on the ServiceTypeGuid, you can return multiple queues from which you will
pick a specific queue to receive a message.
• Label is a text label for the queue. You can search by Label, but you can’t guarantee that
a label is unique in the same way as a GUID.
• CreateTime is the time when the queue was first created.
• ModifyTime is the time when the queue properties were last changed.
• RelServiceType is the relationship parameter for the ServiceTypeGuid, which allows
you to specify a Boolean operator for use in the search. This allows you to search for all
queues that don’t have a certain ServiceTypeGuid, for example.
• RelLabel is the relationship parameter for Label.
• RelCreateTime is the relationship parameter for CreateTime.
• RelModifyTime is the relationship parameter for ModifyTime.
The following code shows how an application might perform a simple search for queues that
meet specified criteria:
‘Declare MSMQ Objects
Dim objQuery As MSMQ.MSMQQuery
Dim objQueueInfos As MSMQ.MSMQQueueInfos
10
ASYNCHRONOUS

‘The following is the ServiceTypeGUID we


APPLICATIONS

‘want to search for


COM+

Const msmqServiceTypeGUID$ = “{581EA041-8D8E-11d1-B101-000629142E7B}”


Business Services
260
PART III

‘Locate all queues that meet the criteria.


Set objQuery = New MSMQ.MSMQQuery

Set objQueueInfos = objQuery.LookupQueue _


(ServiceTypeGuid:=msmqServiceTypeGUID)

MSMQQueueInfos Object
MSMQQueueInfos is the return object from the LookUpQueue method of the MSMQQuery
object. This object contains all the queues that met the search criteria. You can move through
this collection to examine and select a particular queue from the set. The collection has only
two methods associated with it: Next, which moves the collection to the next queue, and
Reset, which returns the collection to the first queue in the set.

The collection of queues returned to the MSMQQueueInfos collection is dynamic and can
change as queues are created and destroyed. As a result, you can’t depend on the count of the
collection remaining constant. Therefore, you use the Next method to work through the collec-
tion while checking each operation to ensure that a valid queue is returned. The following
shows how to walk through a collection of MSMQQueueInfo objects:
‘List the Create Times for all queues that
‘are of a certain ServiceType.
Dim objQuery As new MSMQQuery
Dim objQueueInfo As MSMQQueueInfo

‘Get queues.
Dim objQueueInfos As MSMQQueueInfos

Set objQueueInfos = objQuery.LookupQueue _


(ServiceTypeGuid := “{581EA041-8D8E-11d1-B101-000629142E7B}”)

‘Start with First queue in collection


objQueueInfos.Reset

Set objQueueInfo = objQueueInfos.Next

While Not objQueueInfo Is Nothing


lstQueues.AddItem objQueueInfo.CreateTime
Set objQueueInfo = objQueueInfos.Next
Wend

MSMQQueueInfo Object
The MSMQQueueInfo object represents information for a single message queue. By using this
object, you can create, destroy, open, and close message queues. All the queue parameters are
also available as properties of this object. The MSMQQueueInfo object represents a queue but
Asynchronous COM+ Applications
261
CHAPTER 10

doesn’t represent an open queue in use by an application. Open queues are returned as
MSMQQueue objects from the Open method of the MSMQQueueInfo object. The Open method
of the MSMQQueueInfo object has the following syntax:
Set MSMQQueue = MSMQQueueInfo.Open (Access, ShareMode)

The Access argument determines what type of access is allowed to the queue. Access can be
granted for sending, receiving, or peeking. Peeking at messages in the queue means that they
can be examined but can’t be removed from the queue. The Access argument is specified by
the constants MQ_PEEK_ACCESS, MQ_SEND_ACCESS, and MQ_RECEIVE_ACCESS.
The ShareMode argument determines how multi-user access is handled to a queue. When set to
MQ_DENY_NONE, the queue is available to everyone without restriction. This setting is required if
Access is set to MQ_PEEK_ACCESS or MQ_SEND_ACCESS. When ShareMode is set to
MQ_DENY_RECEIVE_SHARE, two applications can’t receive messages from the queue simultane-
ously. The option is valid only if the Access argument is set to MQ_RECEIVE_ACCESS.

MSMQQueue Object
The MSMQQueue object represents an instance of an open connection to a message queue. By
using this object, your application can send and receive messages from queues. When a queue
is open, message receipt is performed asynchronously as a runtime event that fires in Visual
Basic code.

MSMQEvent Object
The MSMQEvent object traps asynchronous events that occur as the result of message activity
in a queue. The MSMQEvent object is declared WithEvents in Visual Basic code and provides
two events as a result:
• Arrived fires when a queue of interest receives an event.
• ArrivedError fires when a queue has an error delivering a message.
MSMQ events function slightly differently from a standard Visual Basic event handler. In Visual
Basic, using the WithEvents keyword normally establishes an event handler that lasts for the
life of the handling object. In MSMQ, however, an event handler is connected for a single event
only after a call to the EnableNotification method. After an event is received by your applica-
tion, you must explicitly call the EnableNotification method again to receive the next event.
10
ASYNCHRONOUS

NOTE
APPLICATIONS
COM+

The WithEvents keyword is incompatible with COM+ programming, as I will explain


later in the chapter. Therefore, this technique is appropriate only for unconfigured
components.
Business Services
262
PART III

The following code shows how the recipient of a message connects to a queue for asynchro-
nous notification through the MSMQEvent object:
‘Declare an event object to receive
‘notification of new messages in
‘the queue
Private WithEvents objEvents As MSMQ.MSMQEvent

REM: ******************************************
REM: The following snippet connects the events!
REM: ******************************************

‘Declare MSMQ Objects


Dim objQuery As MSMQ.MSMQQuery
Dim objQueueInfos As MSMQ.MSMQQueueInfos
Dim objQueueInfo As MSMQ.MSMQQueueInfo
Dim objQueue As MSMQ.MSMQQueue

Const msmqServiceTypeGUID$ = “{581EA041-8D8E-11d1-B101-000629142E7B}”

‘Before we can receives a message, we must


‘locate the correct queue
Set objQuery = New MSMQ.MSMQQuery

Set objQueueInfos = objQuery.LookupQueue _


(ServiceTypeGuid:=msmqServiceTypeGUID, Label:=”Simple Demo”)
objQueueInfos.Reset

Set objQueueInfo = objQueueInfos.Next

‘Now that we have found the queue,


‘we can open it for receiving
Set objQueue = objQueueInfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE)

‘Since we receive asynchronously,


‘we have to connect the queue to
‘the event object
Set objEvents = New MSMQEvent
objQueue.EnableNotification objEvents

MSMQMessage Object
The MSMQMessage object is used to send and receive data from queues. MSMQMessage
objects are flexible objects that contain properties to describe the message as well as the actual
message data. The MSMQMessage object carries the message data in the Body property, which
Asynchronous COM+ Applications
263
CHAPTER 10

can contain a string, an array of bytes, any numeric, date, and currency type that a Variant can
contain, or any persistent ActiveX object. The following code sends a message to an open
queue:
Set objMessage = New MSMQ.MSMQMessage

With objMessage
.Priority = 4
.Body = txtMessage.Text
.Label = “My Message”
.Send objQueue
End With

QUICK CHECK 10.1

Message Queues
1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 10\Quick Check 10-1. This directory contains a project you can
use to program MSMQ.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 10-1. Copy the contents from the CD-ROM directory into the new
directory.
3. Before creating the COM+ components, you need to create a new queue for this exam-
ple. In the Message Queuing explorer, select the Public Queues folder and then choose
New Public Queue from the Action menu.
4. Name the new public queue and click OK. After the queue is created, right-click it and
open the property sheet. Note the ID for the queue. You will need this ID later to locate
the queue in code.
5. Open the project named comqueue.vbp. This project contains two class modules:
• The Client class sends messages to the queue.
• The Server class retrieves the messages.
Each class locates the queue using the ID you recorded earlier. Replace the ID in
the code with the specific ID for your queue.
10
6. Compile the project into an ActiveX DLL. You won’t place your components in a COM+
ASYNCHRONOUS

application because they won’t work correctly in the stateless environment of COM+.
APPLICATIONS
COM+

7. Locate client.vbs, a Windows Scripting Host file. Double-click the file to run it and
you will be prompted to enter a message for the queue.
Business Services
264
PART III

8. After sending the message, examine the contents of the queue using the Message
Queuing explorer. You should now see your message in the queue (see Figure 10.3).

FIGURE 10.3
A new message will be in the queue.

9. Locate and run the file server.hta. This file starts the server component and connects to
the queue. As messages are cleared from the queue, they are logged into a file named
messages.txt.

MSMQ Limitations
Because MSMQ applications are decoupled from their clients by design, you must have a
mechanism for staying connected to the queue while you wait for messages. This typically
means creating an executable or Windows service that can hold a reference to your component
while it listens. The idea of having a component live for an extended period of time and simply
waiting is an anathema to COM+ developers, but it’s a necessary evil in asynchronous pro-
gramming.
The bigger problem for COM+ programmers is the need to use the WithEvents keyword to
receive event notifications from MSMQ. Declaring variables WithEvents is incompatible with
COM+ programming and should never be done. Therefore, standard MSMQ programming
doesn’t integrate well with COM+. Fortunately, we have an alternative designed specifically
for COM+—namely, Queued Components.
Asynchronous COM+ Applications
265
CHAPTER 10

Queued Components
Queued Components (QC) is an asynchronous COM+ technology based on MSMQ queues.
QC has several advantages over traditional MSMQ programming:
• QC hides the details of queue management from your components. They no longer have
to search for the queue of interest because queues are maintained automatically.
• Queued components can function in a synchronous or asynchronous mode without
knowing how they are being invoked.
• QC offers built-in support for transactions.
• QC can fully integrate with the COM+ event system.
Figure 10.4 shows a conceptual drawing of the QC system.

Client Server
Component Component

Method Security
call context

QC Player
Method Security
call context

QC Recorder QC Listener

Message Queue

COM+ QC System

FIGURE 10.4
QC provides full asynchronous support for COM+.

When a client makes a call to a QC, it actually calls the QC Recorder. The QC Recorder acts
as a proxy for the final server component and accepts the method call from the client. The QC
Recorder also marshals the security context of the client into the message so that it can be used
to determine access to the server component later. 10
ASYNCHRONOUS

The QC Recorder delivers the message to a transacted MSMQ queue, meaning that the mes-
APPLICATIONS

sage is accepted only if any client-side transactions commit. If the QC system is part of an
COM+

aborted transaction, the message from the recorder won’t be allowed in the queue. The queue
stores the message until the server application is started.
Business Services
266
PART III

The server application must be started to receive method calls from the QC system. This is the
same problem we had with MSMQ. A separate process such as an executable or a service must
run the sever component in the COM+ application. However, in addition to the techniques
available with MSMQ, you can start a COM+ application manually in the Component Services
explorer by right-clicking it and selecting Start.
Once the server application is started, the QC Listener retrieves messages from the queue and
delivers them to the QC Player. The QC Player makes the appropriate method calls using the
security context of the initial calling client. The QC then takes appropriate action based on the
calls.

Designing Queued Components


Asynchronous processing requires you to think a little differently when you design your
Queued Components. You should begin with the idea that the QC will operate unattended—
that is, Queued Components don’t have a user interface. Although you can start the COM+
application containing the QC using an executable, the simplest and purest approach is to start
the application manually from the explorer.
Because the QC will operate unattended, you must carefully consider how the component will
provide output. Generally, the work done by the QC will result in a tangible output. This
means that the QC might modify a data store, produce a file, or place an outgoing message in
another queue. In any case, the QC can’t rely on input from any client beyond the original
method call.
Furthermore, because the QC is decoupled from the calling client, it suffers from the same
restrictions we saw in the COM+ event system. The QC can’t return data to the calling client
directly. This means that all methods defined for the QC must use the keyword Sub and all
variables passed into the QC must use the keyword ByVal.

Key Principle
Always define QC methods as subroutines, not functions, and pass all parameters by
value.

Beyond observing these restrictions, you create Queued Components as you would any other
COM+ component. After the component is created, you can install it in a COM+ application.
After the component is in the application, you mark the component as queued in the property
sheet for the application. In the application’s Queuing tab, check the Queued box to establish
queues for the application. Checking the Listen box enables the QC Listener. Messages can’t
be retrieved from the queue unless the listener is activated. Figure 10.5 shows the Queuing tab.
Asynchronous COM+ Applications
267
CHAPTER 10

FIGURE 10.5
Queuing is enabled in the application property sheet.

When you mark an application as queued, COM+ builds a series of private queues in MSMQ.
You can see these queues in the Message Queuing explorer. More than one queue is created to
handle delivery problems. COM+ will attempt to deliver a message several times to the server
when it’s listening. If delivery can’t be accomplished, the message is moved down the line of
queues. Unsuccessful deliveries eventually end up in the application’s “dead-letter queue.”
Figure 10.6 shows the queues created by COM+.

10
ASYNCHRONOUS
APPLICATIONS
COM+

FIGURE 10.6
Several private queues are built for an application.
Business Services
268
PART III

CAUTION
Even though you can name a COM+ application nearly anything you want, certain
characters, such as commas, will cause an error when you mark an application as
queued. This is because MSMQ builds the queues using the name of the COM+ appli-
cation. However, MSMQ doesn’t allow all the characters permitted by COM+.

Although the queues have been created for the COM+ application, there’s no guarantee that the
components in the application meet the requirements for queuing. Therefore, you must also
mark the interface of the QC as capable of receiving queued method calls. If the interface of
the component meets the requirements for queuing, you can mark it as queued in the
Component Services explorer using the property sheet for the interface. Figure 10.7 shows the
Queuing tab for an interface.

FIGURE 10.7
At least one interface on the QC must be marked as queued.

Calling Queued Components


After the QC is installed, the application is designated as queued, at least one interface is
marked as queued, and you are ready to call the QC. Queued Components can be called syn-
chronously or asynchronously as determined by the client. However, this flexibility comes at
the cost of learning a new way to start an object in Visual Basic. Queued Components don’t
use the New or CreateObject keywords. Instead, they use a special process known as a
moniker technique.Monikers aren’t new to Windows, but they generally are to Visual Basic
Asynchronous COM+ Applications
269
CHAPTER 10

programmers. A moniker is simply a formal name. In the QC system, this formal naming dic-
tates whether a QC is invoked synchronously or asynchronously. Clients can use one of two
monikers: The new moniker calls the QC synchronously, whereas the queue moniker calls the
QC asynchronously.
Both the new and queue monikers use Visual Basic’s GetObject() function to return an object
reference that can be used to invoke methods. The new moniker is fairly simple to use. All you
have to do is declare the moniker and follow it with the Programmatic Identifier (ProgID) of
the object you want to call. The following code shows an example of creating a synchronous
connection to a QC:
Set objServer= GetObject(“new:MyQC.Server”)

The queue moniker is a little more difficult. In this case, you still use the new moniker, but it’s
prefixed by the queue moniker. The following code shows how to establish an asynchronous
connection to a QC:
Set objServer= GetObject(“queue:/new:MyQC.Server”)

Along with returning an object reference, the queue moniker also allows you to pass parame-
ters that affect the way the QC operates. Table 10.1 shows these parameters. By using these
parameters, you can affect both the destination queue and message handling. For example, the
following code sends a message with the highest priority for the message and a label to iden-
tify it in the queue:
Set objServer= GetObject(“queue:Priority=7,Label=’Test’/new:MyQC.Server”)

TABLE 10.1 Queue Moniker Parameters


Parameter Description
ComputerName Specifies the computer where the queue can be found
QueueName Specifies the queue to receive the message
PathName Computer and queue formatted as ComputerName/QueueName
FormatName The MSMQ format
AppSpecific An unsigned Integer value
AuthLevel The message authentication level: 0=none, 1=always
Delivery Specifies the delivery option: 0=express, 1=recoverable
EncryptAlgorithm Specifies the encryption algorithm
10
ASYNCHRONOUS

HashAlgorithm Specifies the hash function


APPLICATIONS
COM+

Journal Specifies a journal option: 0=none, 1=dead letter, 2=journal


Label A label for the message
Business Services
270
PART III

TABLE 10.1 Continued


Parameter Description
MaxTimeToReachQueue Specifies maximum time in seconds
MaxTimeToReceive Specifies maximum time in seconds for message to be received
Priority Message priority, 0-7
PrivLevel Specifies privacy level
Trace Specifies trace options

QUICK CHECK 10.2

Simple Queued Components


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 10\Quick Check 10-2. This directory contains a project you can
use to create a QC.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 10-2. Copy the contents from the CD-ROM directory into the new
directory.
3. Open the project named simpleqc.vbp. This project contains a single class named Server
with a method named Receive. This method is declared as a subroutine with all its argu-
ments preceded with the ByVal keyword. All this component does is take an input String
and write it to a log.
4. Compile the project into an ActiveX DLL.
5. Create a new COM+ application named Simple QC. Install the compiled component into
the new COM+ application.
6. Using the property sheet for the application, mark the COM+ application as queued and
check the Listen box on the Queuing tab.
7. Using the Component Services explorer, locate the _Server interface for the component.
Open the property sheet for this interface. On the Queuing tab, mark the interface as
queued.
8. Locate the file named new.vbs, a Windows Scripting Host file that will create a synchro-
nous connection with the QC using the new moniker. Run this file.
9. When prompted, enter a new message. You’ll see that a new message log is created in
your project directory by the QC and that it contains your message. This shows that your
component is operating synchronously. Delete the message log.
Asynchronous COM+ Applications
271
CHAPTER 10

10. Using the Component Services explorer, shut down the COM+ application. This is done
by right-clicking the application and selecting Shutdown.
11. Locate the file named queue.vbs. This file uses the queue moniker to communicate
asynchronously with the QC. Run this file and enter a message when prompted. This
time you won’t see a new message log because the component must be started before it
can receive messages.
12. Using the Component Services explorer, start the COM+ application by right-clicking it
and selecting Start. Now you will see a new message log as the queued messages are
played back to the QC.

Using Queued Components in Transactions


Even though you are processing asynchronously, you’ll still want to perform many operations
within a transaction. Queued Components can participate in transactions in several different
scenarios. These situations include operations that occur on the server as well as the client.
First, Queued Components can enlist in a transaction started on the client side. In this scenario,
a client component might want to send confirmation email to a customer when her order is
taken. This process involves writing the order to the database and then calling a QC that sends
the mail. We already know that MSDTC will take care of ensuring the integrity of the database
operation, but it will also make the operation of the QC part of the transaction. In other words,
the method call sent to the QC will be rolled back if the database transaction fails. To accom-
plish this task, simply mark the QC to support transactions. Figure 10.8 shows a conceptual
drawing of this process.

Business Queued
Component Component
E-Mail
Requires New Send E-Mail Supported Message
Command

Database
Write

SQL Server 10
ASYNCHRONOUS
APPLICATIONS
COM+

FIGURE 10.8
The queued method call will be rolled back along with a failed database transaction.
Business Services
272
PART III

On the server side, QC uses transactions to guarantee the delivery of the message from the
queue to the server component. This means that if a computer should fail in the middle of a
component processing messages, the messages are rolled back and tried again once the affected
computer starts back up. This guarantees delivery of the message from the queue to the compo-
nent only one time.
If the messages from the queue are delivered successfully, the QC can still invoke downstream
components in the transaction. This means that if the delivered message causes a transaction to
abort downstream, the transaction rolls back and the message is placed back in the queue for
retry. When this happens, the message is moved through a series of queues. Each time the mes-
sage is retried and fails, it’s moved to a new queue. Eventually, the message is dropped into a
dead-letter queue and never retried again. The retry process is automated in QC, so you never
have to initiate it yourself.
As with any system, you must be careful about how you establish transactional boundaries. On
the server side, it’s best to have all the transactional data enter through one QC and then enlist
synchronous components to complete the transaction. In this way, the QC acts like a business
object and controls the transaction on the server side of the queue. As an example, Figure 10.9
shows a hypothetical ordering system. Notice how the transactional boundary is defined.

Data Components

Credit Supported
Order
Card
Order Data
Data Business Queued
Product
Component Component Supported Order
Requires New Supported Data
Queue

Shipping
Address Supported SQL Server

Transactional Boundary

FIGURE 10.9
The QC can enlist downstream components in its transaction.

Exception Classes
In some cases, it might be impossible to deliver a message from client to queue, or from the
queue to the server. In these cases, the message will end up in the dead-letter queue on the
client or server. When this happens, COM+ allows you to specify a class that should handle the
exception. To handle the exception, you must create a class that implements the
IPlaybackControl interface. This interface has two methods: FinalClientRetry and
FinalServerRetry.
Asynchronous COM+ Applications
273
CHAPTER 10

Creating an exception handler allows you to take final action to deal with a failed delivery.
This might include rolling back other operations that were completed previously. The excep-
tion handler is registered with the COM+ application on the Advanced tab of the Queued
Component. Figure 10.10 shows this setting.

FIGURE 10.10
QC supports an exception class to handle failed deliveries.

EXERCISE 10.1

Online Flower Shop


This exercise brings together several aspects of Queued Components design to create an online
flower shop. You will use Queued Components in a transaction to accept the initial order over
the Web and use them on the back end to process the order. Because the processing is asyn-
chronous, you’ll create a queued email component to send updates to the customer using
Exchange 2000.
Creating the Database
Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
10
ASYNCHRONOUS

10\Exercise 10-1. This directory contains a partially completed project for the online store.
APPLICATIONS
COM+

Step 2
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
10-1. Copy the contents from the CD-ROM directory into this new directory.
Business Services
274
PART III

Step 3
Before you can begin to build components, you must create the SQL Server database for the
application. Start the SQL Enterprise Manager and use it to create a new database named
eFlowers.

Step 4
After the database is created, start the SQL Server Query Analyzer from the Tools menu and
connect to the eFlowers database.

Step 5
In the Query Analyzer, open the file named eflowers.sql. You can use this SQL script file to
build and populate the database tables. Run the script on the database you created. Figure 10.11
shows the script in the Query Analyzer.

FIGURE 10.11
Create the database tables using the SQL script.

Creating the Email Component


Step 6
Open the project named qcmail.vbp in Visual Basic. This project is a queued email component
that can be called at any time to update the customer with order status. Compile this compo-
nent into an ActiveX DLL.
Asynchronous COM+ Applications
275
CHAPTER 10

NOTE
This component uses the Collaborative Data Objects (CDO) for Exchange 2000. If you
aren’t running Exchange 2000, you might have to modify this code.

Step 7
Create a new COM+ application for the QCMail component named Queued Mail. Using the
application property sheet, check the Queued and Listen boxes on the Queuing tab.

Step 8
Install the QCMail component into the new COM+ application. Using the Component Services
explorer, locate the _Message interface. Open the property sheet for the interface and check
the Queued box on the Queuing tab.

Step 9
Right-click the new COM+ application and select Start to start the QCMail component. It will
wait to send messages.

NOTE
If for any reason the Queued Mail application shuts down, mail won’t be sent. Make
sure that the application is started before you run the final project.

Creating the Data Components


Step 10
Open the project group eflowers.vbg in Visual Basic. This project group contains a project for
reading product data from the database named flowers.vbp and a project for writing the trans-
action from a QC named qcflowers.vbp.

Step 11
Open the code window for the class named Reader. This class is a data component that reads
all the products in the database and returns them as XML.
10
Step 12
ASYNCHRONOUS
APPLICATIONS

Open the code window for the class named GUID. This class generates unique order numbers
COM+

for the system. I find that having a component that can generate unique identifiers is useful in
many systems.
Business Services
276
PART III

Step 13
Compile the project group into two ActiveX DLLs.

Step 14
In the Component Service explorer, create a new COM+ application named Flowers. Install
the Flowers component into the new COM+ application.

Step 15
Open the property sheet for the Reader component. On the Activation tab, enable object con-
struction. Provide a constructor string that can be used to connect to the eFlowers database—
for example,
Provider=SQLOLEDB;Data Source=(local);
Initial Catalog= eFlowers;UID=sa;PWD=pwd;”

Step 16
Create a separate COM+ application named Queued Flowers. On the application property
sheet, check the Queued and Listen boxes on the Queuing tab.

Step 17
Install the QCFlowers component into the new COM+ application. In the Component Services
explorer, locate the _Writer interface. Open the property sheet for the interface and check the
Queued box on the Queuing tab.

Step 18
Right-click the new COM+ application and select Start to start the QCFlowers component. It
will wait to place orders.

NOTE
If for any reason the Queued Flowers application shuts down, orders won’t be
processed. Make sure that the application is started before you run the final project.

Step 19
Open the property sheet for the Writer component. On the Activation tab, enable object con-
struction. Provide a constructor string that can be used to connect to the eFlowers database—
for example,
Provider=SQLOLEDB;Data Source=(local);
Initial Catalog= eFlowers;UID=sa;PWD=pwd;”
Asynchronous COM+ Applications
277
CHAPTER 10

Building the Web Site


Step 20
Start a new Web project using Visual InterDev and name it eFlowers. When prompted in the
New Project Wizard, use the Leaves theme for the new site.

Step 21
Import the files default.asp, form.xsl, and order.asp from the project directory into the
Web project.

Step 22
Most of the interesting action takes place in order.asp. Once the order form is filled out, this
page enlists the COM+ components in a transaction to process the order and send an email to
the customer. The ASP page itself initiates the transaction by using the @TRANSACTION attribute.
(Transactional Web pages are covered in more detail in Chapter 11, “COM+ and the Internet.”)
However, each operation directed by the page is part of a transaction so that the email is sent
only if the order can be committed.

Step 23
Open default.asp in the Internet Explorer. This page uses the Reader component to return all
the products as XML. Form.xsl formats the XML into an order form. Figure 10.12 shows the
form in the browser.

10
ASYNCHRONOUS
APPLICATIONS
COM+

FIGURE 10.12
Use the form to place an order.
Business Services
278
PART III

Step 24
Fill out the form and place an order. If you’ve built the application correctly, you will see a
page thanking you for your order and receive an email confirmation with your order number.
Figure 10.13 shows the email confirmation in Microsoft Outlook.

FIGURE 10.13
The order number is included in the confirmation.

Step 25
You can try to make the transaction fail by typing in a state with more than two letters. This
will cause the transaction to fail because the state field accepts only two characters. You should
receive a message telling you the transaction couldn't be completed. You also won't get an
email message, nor will new data be entered in the database.
PART
User Services
IV
IN THIS PART
11 COM+ and the Internet 281

12 COM+ and Win32 311

13 Integrating COM+ with Groupware 331

14 Debugging and Deploying COM+


Applications 353

15 COM+ Catalog Administration 377


COM+ and the Internet CHAPTER

11
IN THIS CHAPTER
• New Internet Information Server
Features 282

• Creating Transactional Web Pages 290

• Accessing ASP Objects with COM+


Components 298

• Understanding XSL Style Sheets 300


User Services
282
PART IV

Internet Information Server (IIS) version 5 ships with Windows 2000 and continues the tight
integration between COM+ and Web services that began with MTS and IIS 4.0. This integra-
tion provides enhanced scalability and fault tolerance for your COM+ Web applications. Like
its predecessor, COM+ runs your Web-based applications by default—even if you use only
scripted Active Server Pages (ASP). In this chapter, we examine the relationship between IIS
and COM+, with an emphasis on new features.

New Internet Information Server Features


You can create COM+ Web applications by using ASP pages alone or in concert with COM+
components. Most developers prefer the latter because components offer a way to create more
maintainable solutions. Later in this chapter, however, you will see that pure scripting solutions
can be a compelling choice in IIS 5. In any case, IIS 5 offers several new features that are of
interest to Web developers of all stripes. Most of the new IIS features are accessible through
the Internet Services Manager, which is located on the Start menu in the Administrative Tools
group. Figure 11.1 shows the Internet Services Manager.

FIGURE 11.1
The Internet Services Manager provides administrative access to IIS.

Isolating Internet Applications


If you have been working with IIS since its introduction, remember that IIS was initially
designed to run all applications in the same process as the Web server itself (inetinfo.exe).
Originally, Microsoft claimed that this design was superior to the then-popular Common
Gateway Interface (CGI) because in-process applications run faster than out-of-process
COM+ and the Internet
283
CHAPTER 11

applications like CGI. Soon, however, problems began to emerge with this design. Improperly 11
designed applications that crashed while in the same process as the Web server caused the

COM+ AND THE


entire server to fail.

INTERNET
Microsoft addressed the problems with in-process applications by integrating IIS with MTS.
Through this integration, MTS allowed developers to choose to run an application in process or
in a separate isolated process handled by MTS (mtx.exe). By using this scheme, you could
choose the greater speed of in-process applications while acknowledging the risks, or you could
choose the greater safety of isolation in a separate process with the attendant performance hit.
IIS 5.0 enhances these options by providing the choice of running a Web application in a pool.
Doing so allows an application to share a process that is isolated from the Web server with
other Web applications. This represents a sort of “middle-of-the-road” option that gives better
performance with acceptable isolation.
Setting the isolation level for an application first requires that you establish a directory as a
recognized application. IIS applications are directories in which IIS can maintain state infor-
mation. IIS applications are automatically created whenever you create a new Web project in
Visual InterDev. However, you can also create an application boundary for any virtual direc-
tory by using the property sheet for that directory in the Internet Services Manager. Figure 11.2
shows the property sheet where the new application is defined.

FIGURE 11.2
Clicking the Create button defines a new application.

Once the new application is defined, you can choose from the various levels of isolation avail-
able. The default setting, Low, means that the application will run in the memory space of IIS.
A setting of Medium establishes pooled isolation, and a High setting is complete isolation.
Figure 11.3 shows the settings on the property sheet.
User Services
284
PART IV

FIGURE 11.3
Select the appropriate isolation level for your application.

Regardless of the isolation level you select, you will want to know how to unload your applica-
tion for maintenance. This is particularly important when you want to make changes to a com-
ponent that’s running in your Web application because you can’t recompile a Visual Basic
ActiveX DLL if the component is still loaded into memory.
In the past, if you chose no isolation for your application and it used components, you were
stuck rebooting the computer every time you wanted to change the DLL. In the very early days
of IIS development, I can remember rebooting the server dozens of times each day as I tried to
implement some new ISAPI application.
Under IIS 5, you no longer have to worry about rebooting to unload an in-process component
because IIS 5 supports a restart feature that stops and starts Web services without a reboot.
Restarting the Web services will automatically unload any in-process applications, thus freeing
your components for maintenance. Restarting Web services is accomplished through the
Internet Services Manager’s Action menu once you have selected the computer where the
restart is to occur. Figure 11.4 shows the restart dialog.
If you choose to isolate your applications, you will see the integration between IIS and COM+
emerge. Selecting to isolate a Web application creates a new COM+ application, which will
serve as the new process for your Web application. If any part of your Web application fails,
only the COM+ application will crash; the Web server will remain operational.
Unloading isolated processes doesn’t require a Web services restart. To unload an isolated
process, click the Unload button on the property sheet for the application in the Internet
Services Manager. Alternatively, you could choose to shut down the COM+ application associ-
ated with the process. Figure 11.5 shows the COM+ package for pooled applications in the
Component Services explorer.
COM+ and the Internet
285
CHAPTER 11

11

COM+ AND THE


INTERNET
FIGURE 11.4
Restarting unloads in-process components.

FIGURE 11.5
Isolated applications can be unloaded from the Component Services Explorer.

Generating Custom Error Messages


Internet users are all familiar with HTTP errors generated as a result of a problem with a Web
site. For example, the HTTP 404 error is seen commonly when a page can’t be found. IIS
responds to HTTP errors by returning a brief description of the error. This description can be
customized using the property sheet for an IIS application. Figure 11.6 shows the settings for
custom errors.
User Services
286
PART IV

FIGURE 11.6
You can select to generate custom error messages.

When creating custom error messages, you can access either an HTML file specifically associ-
ated with an error, or an ASP file that can perform processing when the error occurs. Using the
ASP file to perform error processing is most interesting when you utilize the Server object’s
new GetLastError method.
ASP processing errors always throw a 500; 100 exception in IIS. By default, this error is asso-
ciated with an Active Server Page named 500-100.asp. This page uses the new ASPError
object that is returned by the GetLastError method to create a customized error page.
Every time an ASP processing error occurs that maps to the 500;100 error, ASP creates a new
ASPError object. This object is then retrieved using the GetLastError method. Once retrieved,
you can use the properties of the object to create the custom error page. Table 11.1 lists the
available properties for the ASPError object.

TABLE 11.1 ASPError Properties

Property Name
Number The standard COM error number
Description The standard COM error description
ASPCode The ASP processing error number
ASPDescription The ASP processing error description
Source The actual source code that caused the error
COM+ and the Internet
287
CHAPTER 11

Property Name 11

COM+ AND THE


Category Indicates if ASP, script, or a COM object caused the error

INTERNET
File Name of the ASP file where the error occurred
Line Line number where the error occurred
Column Column number where the error occurred

QUICK CHECK 11.1

Custom Error Messages


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 11\Quick Check 11-1. This directory contains a set of pages for
creating custom error messages with XML.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 11-1. Copy the contents from the CD-ROM directory into this new
directory.
3. Open the file named errors.asp. You will use this file to gather information from the
ASPError object. This page calls the GetLastError method to access the ASPError
object. All the object’s properties are then converted to an XML stream using an ADO
Recordset. The code in Listing 11.1 shows how the Recordset is built.

LISTING 11.1 Accessing the ASPError Object


Set objRecordset = _
Server.CreateObject(“ADODB.Recordset”)
Set objError = Server.GetLastError
With objRecordset
.Fields.Append “Number”, 200, 200
.Fields.Append “Description”, 200, 200
.Fields.Append “ASPCode”, 200, 200
.Fields.Append “ASPDescription”, 200, 200
.Fields.Append “Source”, 200, 200
.Fields.Append “Category”, 200, 200
.Fields.Append “File”, 200, 200
.Fields.Append “Line”, 200, 200
.Fields.Append “Column”, 200, 200
.Open
User Services
288
PART IV

LISTING 11.1 Continued


.AddNew
.Fields(“Number”).Value = _
CStr(objError.Number)
.Fields(“Description”).Value = _
CStr(objError.Description)
.Fields(“ASPCode”).Value = _
CStr(objError.ASPCode)
.Fields(“ASPDescription”).Value = _
CStr(objError.ASPDescription)
.Fields(“Source”).Value = _
CStr(objError.Source)
.Fields(“Category”).Value = _
CStr(objError.Category)
.Fields(“File”).Value = _
CStr(objError.Number)
.Fields(“Line”).Value = _
CStr(objError.Description)
.Fields(“Column”).Value = _
CStr(objError.Description)
.Update
End With

4. Before we can designate the new ASP page to handle errors, we must create a new appli-
cation directory. Create this new application directory by right-clicking the project direc-
tory and selecting Sharing. Select to expose the project directory on the Web by using the
Web Sharing tab.
5. Once the new Web share is created, you can access its properties in the Internet Services
Manager. Locate the Custom Errors tab and edit the 500;100 errors to be handled by
your new page. Figure 11.7 shows how to make the change.
6. Once your new error page is set up, open your browser and navigate to the page
raise.htm. This page allows you to raise a COM error by simply entering a number.
Enter an error number and you should see the error report generated by the ASPError
object.
7. You can try to generate other script errors by changing the code in raise.asp to throw
an ASP error. For example, try using Server.CreateObject with an invalid ProgID.
Figure 11.8 shows the results of such an error.
COM+ and the Internet
289
CHAPTER 11

11

COM+ AND THE


INTERNET
FIGURE 11.7
Designate your new page to handle custom error messages.

FIGURE 11.8
Hard-code an error to see different messages.
User Services
290
PART IV

Using Scriptless ASP


Active Server Pages work because IIS maps the file extension .asp to the ISAPI application
asp.dll. This means that every time a page is requested with an .asp extension, asp.dll is
loaded and the contents of the page are sent. The results of the processing are then returned to
the browser.
In previous versions of IIS, no distinction was made between pages that contained script and
those that didn’t. If the extension of the page was .asp, it was sent to asp.dll. This meant that
pages without server-side script needed to be given an .htm extension to avoid the overhead of
a call to asp.dll that accomplished nothing. The result was a significant amount of page
renaming as the application was developed.
IIS 5 introduces the concept of scriptless ASP processing. This means that IIS will now per-
form some initial checks on a page with an .asp extension to see if it actually contains server-
side script. If there’s no script in the page, it isn’t sent to asp.dll.
Scriptless ASP isn’t as efficient as coding the file with an .htm extension. However, the new
features are so efficient that now you can simply give all your pages an .asp extension whether
they have a server-side script in them or not. The result will be fewer headaches when perform-
ing site maintenance.

Creating Transactional Web Pages


One of ASP’s most interesting new features is full support for transactional Web pages.
Transactional Web pages allow developers to create complete COM+ applications for the Web
without the use of components. Transactional Web pages are a feature that began under IIS 4,
but finally reaches their true potential under IIS 5. It’s now possible to create solutions that
have many of the same advantages of component-based solutions but are written completely in
script.

Understanding Transactional Attributes


The key to creating transactional Web pages lies in a special COM+ application named IIS
Utilities. This application contains the four ASP ObjectContext components. Each component
corresponds to a different transactional attribute. Figure 11.9 shows the IIS Utilities application.
The secret to starting a transaction in an ASP page is to use the @TRANSACTION directive. This
directive is analogous to the transaction properties you set for a COM+ component in an appli-
cation. The @TRANSACTION directive is always placed as the first line in any ASP page; other-
wise, an error is generated. When you use the directive, the operations performed in any page
COM+ and the Internet
291
CHAPTER 11

are treated as a unit and function in much the same way as work performed by a conventional 11
COM+ component. The @TRANSACTION directive has the following values:

COM+ AND THE


• @TRANSACTION=REQUIRES_NEW—The ASP page will always initiate a new transaction.

INTERNET
This new transaction can enlist other ASP pages if those pages also support transactions.
• @TRANSCTION=REQUIRED—The ASP page will initiate a new transaction if one doesn’t
already exist. However, it might participate in transactions started by other pages.
• @TRANSACTION=NOT_SUPPORTED—The ASP page never initiates a transaction. This is the
default for all ASP pages that don’t specify an @TRANSACTION directive.
• @TRANSACTION=SUPPORTED—The ASP page can participate in transactions started by
other pages. However, if no transaction exists, a new one won’t be started.

FIGURE 11.9
The IIS Utilities package contains the ASP ObjectContext components.

Once the ASP page is set to start a transaction, all work done by script code in the page is part
of the transaction. All work performed by the page will succeed or fail as a batch. Commits
and rollbacks of the work are automatic. Similar to a conventional COM+ component, script
pages aren’t required to specifically call a SetComplete or SetAbort method to commit or roll
back transactions. Instead, ASP provides two transaction events that notify the page of success
or failure: OnTransactionCommit and OnTransactionAbort. A transactional Web page can
User Services
292
PART IV

code both OnTransactionCommit and OnTransactionAbort event handlers that are automati-
cally executed when the transaction succeeds or fails. This means that you can format response
pages to users that indicate success or failure. The code in Listing 11.2 shows a template you
can use for initiating a single-page transaction.

LISTING 11.2 A Simple Transaction Template


<%@Transaction=”REQUIRES_NEW” Language=”VBSCRIPT” %>
<%Option Explicit%>
<HTML>
<HEAD>
</HEAD>
<BODY>
<%

‘Perform Work
‘Database Operation #1
‘Database Operation #2

Sub OnTransactionCommit
Response.Write “<H1>Success!</H1></BODY></HTML>”
End Sub

Sub OnTransactionAbort
Response.Write “<H1>Failure!</H1></BODY></HTML>”
End Sub

%>

Creating Multi-Page Transactions


IIS 4 supported only single-page transactions. Under IIS 5, however, you can now create trans-
actions that span the work performed by multiple ASP pages. This is accomplished by using
two new methods of the Server object: Execute and Transfer. Both methods allow one ASP
page to call another without returning any information to the client browser. This is an impor-
tant distinction because ASP transactions always appear to be a single Web page request from
the browser’s perspective, even if many ASP pages are involved.
The Execute method is simple to understand because it behaves like a function call. When you
use the Execute method, the targeted ASP page is called and any server-side script found there
is executed. After the code is executed, control returns to the original page.
COM+ and the Internet
293
CHAPTER 11

The Transfer method transfers processing to a new ASP page in a manner similar to the 11
Redirect method. The difference is that a Redirect actually requires a round trip to the client

COM+ AND THE


before control is transferred. With the Transfer method, all variables and submitted data are

INTERNET
made available without a round trip. The Transfer method also doesn’t return control to the
original page after processing is complete.
Regardless of which method you use, you can still enlist multiple pages in a transaction by
using the @TRANSACTION directive. The page initially called by the client browser can be desig-
nated as REQUIRES_NEW, and subsequent pages called by Transfer or Execute can be desig-
nated as REQUIRED. This means that the work done by all the pages will be part of the same
transaction.
Consider an example where we want two pages to work together in a transaction. The first
page will initiate the transaction and perform some work. Then that page will enlist a second
page in the transaction through either the Transfer or Execute method. The code in Listing
11.3 shows the first page using the Execute method.

LISTING 11.3 Starting a New Transaction


<%@Transaction=”Requires_New” Language=VBScript %>
<%Option Explicit%>
<HTML>

<BODY>

<H1>First, we start a transaction</H1>

<%Server.Execute “work.asp”%>

<H1>Control returns to the first page</H1>

<%
Sub OnTransactionCommit
Response.Write _
“<H1>Then we commit the transaction</H1></BODY></HTML>”
End Sub

Sub OnTransactionAbort
Response.Write _
“<H1>Then we abort the transaction</H1></BODY></HTML>”
End Sub

%>
User Services
294
PART IV

When multiple pages are involved in a transaction, the output buffer isn’t flushed until all the
pages have done their work. This means that any calls to Response.Write are cumulative in
the transaction process. Therefore, we don’t need to include most of the HTML tags in subse-
quent calls.
The code in Listing 11.4 shows a page that can be enlisted in a transaction.

LISTING 11.4 Enlisting a Page in a Transaction


<%@Transaction=”Required” Language=VBScript %>
<%Option Explicit%>

<H1>Then we perform work in another page</H1>

<%

Sub OnTransactionCommit
Response.Write “<H1>The page votes to commit</H1>”
End Sub

Sub OnTransactionAbort
Response.Write “<H1>The page votes to abort</H1>”
End Sub

%>

Calling the first page in the example from our browser builds a response page that combines
the output of both pages. Also note that each page can have its own set of
OnTransactionCommit and OnTransactionAbort routines, which are executed for each page in
the transaction. Figure 11.10 shows the output from running the example code.
If you modify the first page to call the second using the Transfer method, control won’t gen-
erally return to the original page. This means that the second page can have increased responsi-
bility to format the output. The only exception to this rule is if the original page has coded
OnTransactionCommit and OnTransactionAbort routines. In this case, the appropriate routine
will be executed when the final transaction commits or aborts.

Creating Classes in Scripts


Initially, the idea of creating transactional behavior within ASP pages might not seem attrac-
tive. A legitimate concern is that the pages you create might become unwieldy. Many of us
remember when ASP was first introduced and people would code complete applications in
script. This resulted in huge ASP pages that were nearly impossible to maintain. However,
scripting has made enough improvements over the years to produce a viable approach to
scripted transactions through classes.
COM+ and the Internet
295
CHAPTER 11

11

COM+ AND THE


INTERNET
FIGURE 11.10
The work done by each page is buffered to the output.

Recently, VBScript introduced the concept of creating classes in script through the Class key-
word. This essentially allows you to create a class module using script that functions similarly
to classes created in Visual Basic. The class can have public and private members as well as
properties and methods. As an example, let’s create a Customer class in VBScript. The process
begins with a class declaration as follows:
Class Customer
End Class

Adding properties to the class is handled similarly to creating a property in Visual Basic. First
you code a private data member to hold the state. Then you add accessor and mutator functions
in the form of Property Let and Property Get routines. Listing 11.5 shows how we might
add a simple Name property to the class.

LISTING 11.5 Creating a Simple Property


Class Customer

Private m_Name

Public Property Let Name(strName)


m_Name = strName
User Services
296
PART IV

LISTING 11.5 Continued


End Property

Public Property Get Name()


Name = m_Name
End Property

End Class

Methods are coded for the class by adding Public Functions and Subs. Similar to Visual
Basic classes, the public members of the class are visible outside the class definition, whereas
private members aren’t. The following code shows how a method might be coded into the
class:
Class Customer

Public Function Purchase()


Purchase = “Here’s my money!”
End Function

End Class

Once the class is coded, you create an instance of it by using the New keyword. On creating the
instance, your class can also receive a call to Initialize if you code the routine. Your class
can even receive a Terminate event when it is destroyed. To further enhance the object’s look
and feel, place the class definitions in a separate file and then use the INCLUDE directive to
make them available. A simple example of a page calling our Customer class is shown in
Listing 11.6.

LISTING 11.6 Calling a Class


<%@ Language=VBScript %>
<%Option Explicit%>
<HTML>
<HEAD>
<!-- #INCLUDE File=”customer.cls” -->
</HEAD>
<BODY>

<%

Dim objCustomer
Set objCustomer =New Customer
objCustomer.Name = “Scot”
COM+ and the Internet
297
CHAPTER 11

Response.Write “<H1>” & objCustomer.Name & “</H1>” 11


Response.Write “<H1>” & objCustomer.Purchase & “</H1>”

COM+ AND THE


%>

INTERNET
</BODY>
</HTML>

QUICK CHECK 11.2

Transactional Web Pages


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 11\Quick Check 11-2. This directory contains a set of pages for
investigating transactions.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 11-2. Copy the contents from the CD-ROM directory into this new
directory.
3. Start a new project in Visual InterDev and name it TxASP. Use the Leaves theme when
you create the project. Add all the project files to the new Web project.
This example uses transactional Web pages to place an order for flowers. This project
assumes that you’ve already built the required SQL Server database and components
from Exercise 10.1 in Chapter 10, “Asynchronous COM+ Applications.”
4. Open the global.asa file. In this file, you will find a database connection string. Modify
this string for use with your installation of SQL Server.
5. Open the file default.asp. This file shows all the available products for purchase. The
file uses a scripted class defined in a separate file to read the database and return an
XML stream. XSL is then used to format the results into a table.
6. The transaction begins with the page order.asp. This page begins a new transaction and
enlists the pages writecustomerinfo.asp and writeorderinfo.asp to make the neces-
sary database entries. If the transaction is successful, you are thanked for your order.
Otherwise, you receive an error message.
7. Because the default behavior for any Web application is to redirect to the 500;100 cus-
tom error page, you must disable this redirection. To get the appropriate transactional
behavior, set the 500;100 error message back to its default value. This will prevent a
redirection to the error page and guarantee that the OnTransactionAbort procedure is
executed.
User Services
298
PART IV

8. Run default.asp and place an order. You can test an aborted transaction by typing more
than two letters for the state. This will abort the transaction because the data field for
state is only two characters long.

Accessing ASP Objects with COM+ Components


Many techniques we discuss are geared toward reducing the amount of code in ASP pages.
This is intended to improve Web application maintainability. Therefore, we offload processing
to COM+ components and formatting to XSL style sheets. However, we still find that we must
use the ASP Request object to format arguments for the COM+ components and then the
Response object to return the results. By using COM+ objects, however, we can even remove
these functions from the ASP page.
COM+, like MTS before it, supports accessing all the ASP objects within a COM+ component.
This means that if an ASP page creates an instance of your COM+ component, the component
can in turn access the page’s Request and Response objects. Using this feature, we can handle
much of the input and output work of the Web application in a COM+ component.
COM+ allows access to the ASP objects through the context object. When the COM+ compo-
nent is called from an ASP page, the objects for the calling page become a collection of the
context. The following code shows the syntax for accessing the objects:
Dim objContext As COMSVCSLib.ObjectContext
Set objContext = GetObjectContext

Context(“Request”)
Context(“Response”)
Context(“Session”)
Context(“Application”)
Context(“Server”)

The objects’ primary use is handling submitted form data and writing out response data. At
first, it might seem like a bad idea to create HTML output inside a Visual Basic component.
After all, if you specify a significant amount of HTML, you have to recompile the component
for any change to a Web page. For example, the code in Listing 11.7 generates an HTML table
and would be difficult to maintain.

LISTING 11.7 Creating an HTML Table


strHTML = “”
strHTML = strHTML & “<TABLE><TR><TH>Name</TH>”
strHTML = strHTML & “<TD><INPUT></TD></TR><TR>”
strHTML = strHTML & “<TH>Address</TH><TD><INPUT>”
COM+ and the Internet
299
CHAPTER 11

strHTML = strHTML & “</TD></TR><TR><TH>City</TH>” 11


strHTML = strHTML & “<TD><INPUT></TD></TR><TR>”

COM+ AND THE


strHTML = strHTML & “<TH>State</TH><TD><INPUT>”
strHTML = strHTML & “</TD></TR><TR><TH>Zip</TH>”

INTERNET
strHTML = strHTML & “<TD><INPUT></TD></TR>”

objContext(“Response”).Write strHTML

The real value of this technique, however, can be seen when you use style sheets to format
XML output. In this case, a style sheet can be applied to an XML stream using the MSXML
parser. In this case, the HTML is generated automatically by the style sheet. Therefore, any
changes to the HTML output require only a change to the style sheet.
We already know how to use the ADO Stream object to return an XML stream. All we
need to do is use the MSXML parser to apply the style sheet. A style sheet is really nothing
more than a specialized XML page. Thus, it can be loaded into the MSXML parser like any
XML page. The following code shows how to load a style sheet named table.xsl into the
parser:
Dim objXSLDOM As MSXML.DOMDocument
Set objXSLDOM = New MSXML.DOMDocument

objXSLDOM.Load “table.xsl”

The parser’s Load method loads XML from a file. If you want to load from a stream, use the
LoadXML method. This allows us to load a separate instance of the parser with the recordset
returned from an ADO Stream object. The following code shows how to load a recordset into
the parser:
objRecordset.Save objStream, adPersistXML
strXML = objStream.ReadText

Set objXMLDOM = New MSXML.DOMDocument

objXSLDOM.LoadXML strXSL

Once the XML and XSL are loaded into separate parsers, you can use the XSL to transform
the XML into HTML through the TransformNode method. Once it’s transformed, use the
Response object to return HTML to the client. The following code shows how to create and
send the HTML:
strHTML = objXMLDOM.transformNode(objXSLDOM)
objContext(“Response”).Write strHTML
User Services
300
PART IV

Understanding XSL Style Sheets


Throughout the book, we have used XSL style sheets to format output to the browser. Like all
style sheets, XSL is useful for separating content from format. My goal in this section is to
provide a basic overview of XSL that will form a foundation for understanding the examples in
the book. Note, however, that both XML and XSL are changing, and that the final implementa-
tions of these technologies will likely be somewhat different.

XSL Fundamentals
XSL provides instructions for transforming an XML file into another format. Although we
often transform the XML into HTML, this isn’t required. XSL could easily be used to trans-
form one XML file into another. In general, the idea is to separate the actual data from the
form in which it’s used.
XSL sheets are associated with an XML file through a processing instruction, a line in an
XML file that is surrounded by the delimiters <? ?>. These delimiters indicate a relationship,
function, or identification. XML files themselves are identified using a processing instruction.
The following code identifies an XML file and associates it with an XSL sheet:
<?xml version=”1.0”?>
<?xml:stylesheet type=”text/xsl” href=”mysheet.xsl”?>

When an XML file is sent directly to an XML-enabled browser, the browser uses its own
parser to transform the XML data into HTML as directed by the style sheet. This means that
XML-enabled browsers can request XML pages directly from a site. If the target browser isn’t
XML-enabled, the transformation must take place on the Web server before the final page can
be delivered. This is done with the MSXML parser and Active Server Pages.
Once you have an association between the data and the style, you must define the style sheet to
represent the information properly. XSL uses a template system based on patterns found within
the XML data. Using these patterns, you can specify how to format certain parts of the data
generically so that it makes the style separate from the data. The only true dependency between
XSL and XML is that you must generally know something about the data structure within the
XML file to successfully write an XSL file.
As an example, use a simple XML file that contains information from a company memo.
Because XML allows you to create your own tags, we might divide the memo into pages and
then further divide a page into paragraphs. On the start page we’ll include some information
identifying the sender and the subject. Furthermore, we’ll associate our file with a style sheet
that we’ll create later. Listing 11.8 shows the resulting XML file.
COM+ and the Internet
301
CHAPTER 11

LISTING 11.8 A Simple XML File 11

COM+ AND THE


<?xml version=”1.0”?>
<?xml:stylesheet type=”text/xsl” href=”memo.xsl”?>

INTERNET
<MEMO>
<PAGE Number=”1”>
<DATE>1 June 2000</DATE>
<FROM>The President</FROM>
<SUBJECT>Donuts</SUBJECT>
<PARAGRAPH>
I have noted that the donuts found at company
meetings recently have been substandard. All
employees are hereby directed to purchase
donuts only from the list of authorized refreshment
vendors attached.
</PARAGRAPH>
<PARAGRAPH>
That is all.
</PARAGRAPH>
</PAGE>
<PAGE Number=”2”>
<PARAGRAPH>
List of authorized refreshment vendors:
<LIST Item=”Good Donuts”/>
<LIST Item=”Big Donuts”/>
<LIST Item=”Sweet Donuts”/>
<LIST Item=”Fun Donuts”/>
</PARAGRAPH>
</PAGE>
</MEMO>

If you are new to XML, keep in mind a couple of things about creating an XML file:
• You can use any tags you want. That’s right—just make them up!
• All tags must be well formed. This means that every opening tag must have a closing
tag, and they must be properly nested. The exception to this rule is that a single tag is
fine if it acts as its own closing tag. You can see this in Listing 11.8 with the <LIST>
tag. The tag has a forward slash at the end to indicate that it functions as its own clos-
ing tag.
Once the XML file is created, you can turn your attention to creating the XSL. XSL files must
follow the exact same rules as XML files. They must be well-formed and, just like XML, they
are case sensitive. Because XSL is really just a specialized XML file, you have pre-defined
User Services
302
PART IV

tags to choose from when creating the file. These tags form a sort of programming language
that let you format the data. Every XSL file, however, begins with a stylesheet tag identify-
ing the file as XSL. The following code shows how to begin the style sheet:
<xsl:stylesheet xmlns:xsl=http://www.w3.org/TR/WD-xsl
xmlns:HTML=”http://www.w3.org/Profiles/XHTML-transitional”>

</xsl:stylesheet>

XSL Templates
Inside the stylesheet tags, you define templates. Templates match the structure of the XML
file with the style sheet’s formatting instructions. The root template always defines the starting
point for the page and handles most of the fundamental HTML formatting required to show the
file in a browser. Listing 11.9 shows the root template for the example.

LISTING 11.9 Root XSL Template


<xsl:stylesheet xmlns:xsl=http://www.w3.org/TR/WD-xsl
xmlns:HTML=”http://www.w3.org/Profiles/XHTML-transitional”>

<!-- The template for the page -->


<xsl:template match=”/”>
<HTML>
<HEAD>
<TITLE>Memorandum</TITLE>
</HEAD>
<BODY>
<DIV>
<P><xsl:value-of select=”MEMO/PAGE/DATE”/></P>
<H2><xsl:value-of select=”MEMO/PAGE/FROM”/></H2>
<H2><xsl:value-of select=”MEMO/PAGE/SUBJECT”/></H2>
</DIV>
<xsl:apply-templates select=”MEMO/PAGE”/>
</BODY>
</HTML>
</xsl:template>

</xsl:stylesheet>

The root template is always designated by the match criteria /. Inside the root template, we
have used the value-of tag to select the date, subject, and sender for the memo. This is the
simplest way to select data from the XML file. Simply select it based on the path that you want
to follow.
COM+ and the Internet
303
CHAPTER 11

XSL allows you to select information from the tag or attributes associated with the tag. For 11
example, our <PAGE> tag has an attribute, Number, associated with it. To select data from an

COM+ AND THE


attribute, use the @ designator. The following code shows how to select the page number

INTERNET
attribute:
<xsl:value-of select=”MEMO/PAGE/@Number”/>

In addition to selecting directly, we quite often want to perform an operation on every element
in a file. For example, we want to display each page in a memo regardless of how many pages
there are. Displaying repetitive tags requires you to create a separate template for the re-
peated elements. You can then invoke the new template from the root template by using the
apply-templates tag. In the root of our memo, we invoke a template for the pattern
MEMO/PAGE. The template is defined by the following code:

<xsl:template match=”PAGE”>
</xsl:template>

Within the new template, we want to loop through every page and display the information.
Loops are created with the for-each tag. The loop can be designed to select any tag or
attribute in the file. After a tag is selected, you use the value-of tag to display the information:
<xsl:template match=”PAGE”>
<DIV>
<xsl:for-each select=”PARAGRAPH”>
<P><xsl:value-of/></P>
</xsl:for-each>
</DIV>
</xsl:template>

In addition to the paragraph, we also want to loop through any list tags that might be on the
page. This is accomplished through a nested loop. Listing 11.10 shows the complete XSL file
for the example. Figure 11.11 shows the completed example viewed in the browser.

LISTING 11.10 Complete Style Sheet


<xsl:stylesheet xmlns:xsl=http://www.w3.org/TR/WD-xsl
xmlns:HTML=”http://www.w3.org/Profiles/XHTML-transitional”>

<!-- The template for the page -->


<xsl:template match=”/”>
<HTML>
<HEAD>
<TITLE>Memorandum</TITLE>
</HEAD>
<BODY>
<DIV>
User Services
304
PART IV

LISTING 11.10 Continued


<P><xsl:value-of select=”MEMO/PAGE/DATE”/></P>
<H2><xsl:value-of select=”MEMO/PAGE/FROM”/></H2>
<H2><xsl:value-of select=”MEMO/PAGE/SUBJECT”/></H2>
</DIV>
<xsl:apply-templates select=”MEMO/PAGE”/>
</BODY>
</HTML>
</xsl:template>

<!-- The template for the pages -->


<xsl:template match=”PAGE”>
<DIV>
<xsl:for-each select=”PARAGRAPH”>
<P><xsl:value-of/></P>
<xsl:for-each select=”LIST”>
<LI><xsl:value-of select=”@Item”/></LI>
</xsl:for-each>
</xsl:for-each>
</DIV>
</xsl:template>

</xsl:stylesheet>

FIGURE 11.11
XSL transforms XML into a new format.
COM+ and the Internet
305
CHAPTER 11

XSL Elements 11

COM+ AND THE


XSL is a large topic, and a full treatment is beyond the scope of this book. However, I have
assembled a mini guide to the key XSL elements. The information contained here should be

INTERNET
enough to get started and understand the examples in this book. The following sections give a
listing of the key XSL elements and a brief explanation.

value-of
The value-of tag returns the value of any tag or attribute. You can use the tag with an explicit
or relative path. Use the @ operator to access an attribute.
<xsl:value-of select=”MEMO/PAGE/SUBJECT”/>
<xsl:value-of select=”MEMO/PAGE/@Number”/>
<xsl:value-of/>

for-each
The for-each tag loops through a set of repeated data within an XML file. You can use it to
loop through tags or attributes. It works with explicit or relative paths. The tag also allows the
use of a wild card to match the selected pattern (for example, @* for all attributes).
<xsl:for-each select=”MEMO/PAGE/PARAGRAPH”></xsl:for-each>
<xsl:for-each select=”PARAGRAPH”></xsl:for-each>
<xsl:for-each select=”@*”></xsl:for-each>

if
The if tag allows you to create simple if-then structures. It uses a conditional test to deter-
mine if processing occurs. The syntax is a little strange for VB programmers. The following
shows how to test for equal and not equal values respectively:
<xsl:if test=”@Number[.=’1’]”></xsl:if>
<xsl:if test=”@Number[.!=’1’]”></xsl:if>

choose
The choose tag is similar to a Select Case statement in Visual Basic. It allows for multiple
conditional testing. The choose tag uses the when tag to create the branches for each test. The
otherwise tag defines what happens if none of the tests are met.

<xsl:choose>
<xsl:when test=”@au_lname[.=’Green’]”>
<TD STYLE=”font-family:arial;font-size:14pt;”>
<xsl:value-of select=”@au_lname”/></TD>
<TD STYLE=”font-family:arial;font-size:14pt;”>
<xsl:value-of select=”@title”/></TD>
</xsl:when>
<xsl:when test=”@au_lname[.=’Locksley’]”>
<TD STYLE=”font-family:arial;font-size:12pt;”>
User Services
306
PART IV

<xsl:value-of select=”@au_lname”/></TD>
<TD STYLE=”font-family:arial;font-size:12pt;”>
<xsl:value-of select=”@title”/></TD>
</xsl:when>
<xsl:otherwise>
<TD><xsl:value-of select=”@au_lname”/></TD>
<TD><xsl:value-of select=”@title”/></TD>
</xsl:otherwise>
</xsl:choose>

element
The element tag defines an element when you can’t do it directly in XSL. You can run into this
situation because XSL requires you to create well formed output, as discussed earlier. This can
be problematic when you want to create an <INPUT> tag, for example. The following example
shows how to use XSL to create a text box:
<xsl:element name=”INPUT”>
<xsl:attribute name=”NAME”>txtEMail</xsl:attribute>
</xsl:element>

Online Shopping Cart


This exercise uses several of the techniques discussed in the chapter to create a simple online
shopping cart. The cart is maintained in a database on the server. XSL and COM+ objects are
used to format the display of books from the pubs database and the contents of the shopping
cart.

EXERCISE 11.1

Creating the Cart Database


Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
11\Exercise 11-1. This directory contains a partially completed project for the online store.

Step 2
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
11-1. Copy the contents from the CD-ROM directory into this new directory.

Step 3
Although the products for this exercise come from the pubs database, we need to create a sepa-
rate database for the shopping cart information. Start the SQL Server Enterprise Manager and
create a new database named Carts.
COM+ and the Internet
307
CHAPTER 11

Step 4 11
From the SQL Enterprise Manager, start the SQL Query Analyzer. Connect to the Carts data-

COM+ AND THE


base and open the file carts.sql. This is the SQL script to create the tables and stored proce-

INTERNET
dures for the exercise. Run the script on the Carts database.
Creating the COM+ Components
Step 5
Open the file named carts.vbg. This project group contains two projects:
• Shopbiz.vbp is the business layer, which uses the context object to access the input para-
meters and form an output using XSL.
• Shopdata.vbp performs all the data access necessary to read and write to the shopping
cart. Any read information is sent as XML to the business layer for transformation to
HTML.
Step 6
Shopdata.vbp contains two String constants in the declarations section for connecting to the
databases. Examine these constants and modify them as necessary to connect to your database.

Step 7
Shopbiz.vbp contains a single String constant that’s the URL path to this project’s Web site.
You will create the Web site in the next section. Make sure that this constant is appropriate for
your configuration.

Step 8
Compile the projects into two ActiveX DLLs. Create a new COM+ application for the projects
named Carts. Add both components to the new application.
Creating the Web Site
Step 9
Create a new Web project in Visual InterDev named Carts. When prompted, select to use the
Blueprint theme. The XSL style sheets in the exercise use this theme.

NOTE
The Blueprint theme is part of the extended theme pack associated with Visual
InterDev. If this theme doesn’t appear in the New Project wizard, install it with Disk 1
of Visual Studio 6.
User Services
308
PART IV

Step 10
Import the files default.asp, toolbar.asp, cart.asp, cart.xsl, books.asp, and books.xsl
into the new Web project.

Step 11
Open the file books.asp. This file calls the business object and receives results as HTML for-
matted from the XML recordset delivered by the data component. Notice how little code there
is in the page.

Step 12
Open the associated XSL sheet books.xsl. Study this file carefully. Notice how the XSL tem-
plates are used to create a form for each returned title. You can add books to the cart by sub-
mitting this form. Figure 11.12 shows the list of books generated by the style sheet.

FIGURE 11.12
The book list is returned as HTML in several forms.

Step 13
Open the XSL sheet for the shopping cart, cart.xsl. This file formats the cart data and allows
you to remove an item from the cart. Figure 11.13 shows the shopping cart data.
COM+ and the Internet
309
CHAPTER 11

11

COM+ AND THE


INTERNET
FIGURE 11.13
Items can be removed from the shopping cart.

Step 14
Run the application. Add and remove items from the cart.

Step 15
This cart doesn’t allow you to change the quantities in the cart, but the data field is present in
the database. Using what you have learned, try creating a way to change the quantities in the
cart.
COM+ and Win32 CHAPTER

12
IN THIS CHAPTER
• Maintaining Application State 312

• User Interface Strategies 319


User Services
312
PART IV

Is the Visual Basic form dead? When I was working on the MTS version of this book 18
months ago, I would have said no because nearly all the examples in the book used VB forms
as the front end. Now things have changed completely and with so many different technologies
available to call COM+ components, it seems that the forms package is on life support.
Still, there are reasons to create a classic front end for your COM+ applications:
• No other front end has approached the level of interactivity offered by a VB form. In
fact, forms have such a high level of interactivity with the user, many people now simply
refer to them as rich front ends.
• Creating a form-based front end makes the computing power of the client machine avail-
able to your application.
Of course, forms have their disadvantages as well. When a form is used, it must be installed on
the client machine. Although this process can be simplified through the use of group policies
and the Microsoft Installer (covered in Chapter 14, “Debugging and Deploying COM+
Applications”), it still requires an extra level of administration. Forms are also difficult to
maintain. Most developers create highly specialized forms for their applications and place them
in a single executable, often resulting in hundreds of forms in a single project. If any form has
to be changed, the whole project must be opened, increasing the chance that an incorrect
change will be made.
This chapter looks at some practical ideas for implementing Win32 front ends intended to run
on the desktop. You’ll learn how to use the client machine for maintaining state as well as
workflow. I’ll provide some practical techniques for breaking down forms into smaller groups,
and cover the lightweight Win32/HTML hybrid solution.

Maintaining Application State


One advantage of installing components on the client machine is that you can create a true
state layer for your application. In most of the designs covered in this book so far, state is
maintained either on the client as cookies or in the back end database. Although these solutions
work fine for thin client applications, they force compromises in your design. On the other
hand, a Win32 client can run a fully featured user services layer.
When you create a rich user services layer, you will discover that it actually consists of two
layers. The new state/workflow layer is an object model that allows you to manage state and
workflow for each client without resorting to cookies or round trips to the database. The
state/workflow layer properly resides between the business and user services layers of the
application. Following this design, you will create a “four-tier” application.
COM+ and Win32
313
CHAPTER 12

Like all tiers in a distributed application, the state/workflow layer relies on a transport and a
payload to move data. The transfer of data defines the boundary between the state/workflow
layer and the business services layer. After the state/workflow layer receives the data from the
business services layer, it must be converted to a format appropriate for display by creating a
custom collection.
After the transport returns data to the state/workflow layer, the payload is used to create
objects that maintain the state of the application. These objects are stored in a collection that
populates the graphic user interface (GUI), which defines the user services layer. In this way,
the user services layer is decoupled from the state and workflow of the application. Figure 12.1 12
shows how a payload is used to create a collection.

COM+ AND
WIN32
Data Data Data Object
Data Data Data
Object
Data Data Data
Data Data Data Object
Data Data Data Object
Data Data Data Payload To Business
Object Service Layer
Data Data Data
Object

Object

GUI Collection Transport


User Services Layer State/Workflow Layer

User Services Layer

FIGURE 12.1
Rich clients allow the creation of a state/workflow layer.

Many developers ask why insulating the transport from the display through a collection is nec-
essary. Why not simply show a disconnected recordset in data-bound controls? Although it’s
possible to show a disconnected recordset using simple data-bound controls, it allows direct
access to the underlying data set without any control over what users can edit. Encapsulating
the payload within an object allows you to place data validation code within your custom
objects as well as build read-only properties that can’t be edited. Also, isolating the payload
from the GUI means that you can change the transport without affecting the display. Suppose
that you changed the data transport from a recordset to a string. If you’re using data-bound
controls, the GUI will break. If you use a collection, the GUI won’t have to be edited. This
example shows conclusively that state and workflow are truly separate tiers.
User Services
314
PART IV

Key Principle
Data returned from the business layer to the client should be separated from the GUI
by a custom collection class.

Custom Collections
Custom collections have a significant role in the COM+ application because they form the par-
tition between the disconnected recordset and the GUI; therefore, their design will be carefully
considered. The main design consideration for collections is standardization. You will use poly-
morphism to define the structure of all custom collections in COM+ applications just as in the
case of defining communication points between layers.
The collection classes we design will take their structure from the standard Visual Basic
Collection object defining three methods and one property that have become the de facto
standard for all collections. The standard methods for a collection include Add for adding new
objects, Remove for taking objects out of the collection, and Item for accessing one particular
object. The standard collection also describes a single property —Count—for determining how
many items are in the collection. Therefore, we define an interface named ICollection that
defines the Add, Remove, Item, and Count members. Listing 12.1 shows the definition of this
interface.

LISTING 12.1 The Icollection Interface


Public Sub Add(ParamArray vArray())
‘The Add method takes a ParamArray
‘full of data for the new item to add
‘to the collection
End Sub

Public Sub Remove(vKey As Variant)


‘The Remove Method removes
‘an item from the collection
End Sub

Public Function Item(vKey As Variant) As UserInterfaces.IItem


‘This returns an item from the collection
End Function

Public Property Get Count() As Long


‘Return number of items in collection
COM+ and Win32
315
CHAPTER 12

End Property

Public Property Get NewEnum() As IUnknown


‘Supports For...Each
End Property

The ICollection interface can be modified to meet your organization’s particular design
needs; however, the point is that the standard exists. The ICollection interface guarantees that
every collection created for a COM+ application has the same essential features. Notice that
this definition even ensures support for the For-Each syntax through the NewEnum method. 12
The ICollection interface describes the structure of a collection and is responsible for con-

COM+ AND
taining the items within it. However, you can’t predict at the outset what objects you want in

WIN32
the collection—these objects might include authors, publishers, titles, or any other objects you
create from the database. Because you don’t know the nature of an object contained within the
collection, you must define an interface for items that belong to a collection This interface
called IItem is implemented by any object that wants to be a member of a collection and
ensures that each object has a primary key. The following code shows the definition for the
IItem interface:

Public Property Get Key() As Variant


End Property

Public Property Let Key(varKey As Variant)


End Property

Collection classes in COM+ applications are created when a transport is returned from the
business layer. When the collection is created, it can easily be used to display data in the GUI.
Users of the application can then manipulate the GUI and edit the individual objects within the
collection. When the user finishes editing the objects in the collection, a new transport can be
sent with a payload containing the modified data and then sent back to the middle tier to
attempt a batch update.

Data Binding
If your transport consists of recordset objects, you can take advantage of Visual Basic’s data
binding features to simplify your coding. Data binding allows you to tie the properties of an
object in the collection directly to fields in a disconnected recordset. Visual Basic provides a
built-in object named BindingCollection to manage the binding of object properties to
recordset fields. Using BindingCollection to map fields to properties is known as simple
binding.
User Services
316
PART IV

To use BindingCollection, you must first set a reference to the Microsoft Data Binding
Collection and then create an instance of BindingCollection in the Initialize event. After
the instance is created, you have to set BindingCollection’s DataSource property to the ADO
Recordset object you want to bind to your class. Then for each property in the class, you must
use BindingCollection’s Add method to bind the field to the property.

QUICK CHECK 12.1

Simple Binding
1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 12\Quick Check 12-1. This directory contains a partially complete
project you can use to investigate simple data binding.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 12-1. Copy the contents from the CD-ROM directory into this new
directory.
3. Open the project group named simple.vbg. In the Project Explorer, you will find two
ActiveX DLL projects and a Standard EXE project.
4. In the Project Explorer, locate the project named simplebind.vbp. In the project, open
the code window for the class named Title. This class will be simple bound to a discon-
nected recordset.
5. This class already has several property procedures defined representing data returned
from the business services layer. There’s also a procedure named Populate that’s called
by the front end to retrieve the data and bind the properties. This procedure uses the
BindingCollection object. The following code shows the Populate method:
‘Run the Query
Set objRecordset = objData.GetData(strAuthor)

‘Bind Data
Set objBind.DataSource = objRecordset
objBind.Add Me, “TitleID”, “title_id”
objBind.Add Me, “Title”, “title”
objBind.Add Me, “Author”, “au_lname”
objBind.Add Me, “Publisher”, “pub_name”
The Title class acts as a pseudo collection. The bound recordset is used as the collection
of data, and the property procedures allow direct access to the fields in the current
record.
COM+ and Win32
317
CHAPTER 12

6. Examine the MoveNext and MovePrevious methods. These methods move the cursor in
the recordset contained within the class. The properties are then automatically updated
by the BindingCollection object.
7. Open the project named dataserviceprocs.vbp. This data class returns a recordset.
Modify the connect string in this component to match your configuration.
8. Compile the project group.
9. In the Component Services explorer, create a new COM+ application named Simple
Bind. Install the data component into the new application.
10. Run the executable frontend.exe to open a form with which you can use the simple 12
bound data to browse author and title information. Use the next and previous buttons to

COM+ AND
navigate authors that have more than one book associated with them. Figure 12.2 shows

WIN32
the completed project.

FIGURE 12.2
This form uses simple binding to display data.

Simple data binding provides a way to map fields and properties in a one-to-one relationship.
For maximum flexibility, however, you can encapsulate an entire recordset within a collection
through complex binding, allowing you to expose a recordset without hard-coding the names of
properties in a containing object. It also allows you to change the fields returned in a recordset
without changing the collection code.
Complex binding is implemented by setting the DataBindingBehavior of a class module to
vbComplexBound. This setting causes Visual Basic to add DataSource and DataMember proper-
ties to the class. The DataSource property receives an entire recordset, whereas the
DataMember property can designate which values you want the class to expose. When you use
this methodology, you typically expose data through a Properties collection in your class.
User Services
318
PART IV

QUICK CHECK 12.2

Complex Binding
1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 12\Quick Check 12-2. This directory contains a partially complete
project you can use to investigate simple data binding.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 12-2. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Open the project group named complex.vbg. In the Project Explorer, you will find two
ActiveX DLL projects and a Standard EXE project.
4. In the Project Explorer, locate the project named complexbind.vbp. In this project, open
the class module named Titles. This class will be complex-bound to a returned discon-
nected recordset.
5. Select the Titles class in the Project Explorer. In the Properties window, locate the
DataBindingBehavior property and set it to vbComplexBound. When you set this prop-
erty, Visual Basic will automatically add the DataSource and DataMember properties.
Add code to these properties to create the following result:
Public Property Get DataSource() As DataSource
Set DataSource = objRecordset
End Property

Public Property Set DataSource(ByVal objDataSource As DataSource)


Set objRecordset = objDataSource
End Property

Public Property Get DataMember() As DataMember


DataMember = m_DataMember
End Property

Public Property Let DataMember(ByVal DataMember As DataMember)


m_DataMember = DataMember
End Property

6. Examine the Populate method. This method uses the DataMember value as a parameter
to pass to the business services layer. The business services layer then returns a recordset
that is exposed through the Properties method. Examine the Properties method to see
how the fields are exposed.
7. Compile the project group.
COM+ and Win32
319
CHAPTER 12

8. In the Component Services explorer, create a new COM+ application named Complex
Bind. Install the data component into the new application.
9. Run the executable frontend.exe. This will open a form where you can use the simple
bound data to browse author and title information. Use the next and previous buttons to
navigate authors that have more than one book associated with them. Figure 12.3 shows
the completed project.

12

COM+ AND
WIN32
FIGURE 12.3
This form uses complex binding to display data.

User Interface Strategies


After you partition the state from the user services, you are ready to consider techniques for
displaying the data. Our goal here is to come up with practices that minimize the number of
forms you have to create while improving maintainability. In the following sections, we inves-
tigate the use of ActiveX controls as substitutes for forms and the use of lightweight HTA
pages.

ActiveX Controls
ActiveX controls are normally thought of as building blocks of the user interface and not the
user interface itself. However, Visual Basic has introduced two features during the last few
years that might change the way you look at ActiveX controls:
• The ability to create your own ActiveX controls directly in Visual Basic
• The ability to load those controls dynamically at runtime
The ActiveX control project has been part of Visual Basic for some time. By using this project
type, you can create your own ActiveX controls that can be used on any VB form. Although
this capability was released with much fanfare several years ago, the truth is that these controls
have never had great performance. I witnessed several projects where this capability was used
extensively, and the result was a set of forms that took an extremely long time to load.
User Services
320
PART IV

Some companies then used them as custom controls inside Web pages. This capability was
made possible through the <OBJECT> tag that enabled any COM object to be instantiated inside
an HTML page. Again, although this technology was hyped, it turned out to be of little inter-
est. Because COM objects are executable content, downloading and installing them across the
Internet raised serious security concerns.
Even if you get past all the performance and security concerns, building your own ActiveX
control is difficult because VB doesn’t support inheritance. This means that you can’t create
your own ActiveX control by starting with already available capabilities. Suppose that you
wanted to make your own edit control. This control would function exactly like a text box,
except that you could reject certain keys, such as dashes or numbers. Wouldn’t it be nice to just
take a standard textbox and extend it to have the new functionality? Unfortunately, you can’t
do this easily in VB. Because Visual Basic doesn’t support inheritance, you must rebuild much
of the functionality in the existing text box before you can add just a single new feature. So for
a long time now, ActiveX control projects have been part of Visual Basic, but no one really
seems to use them.

Control Fundamentals
Engineers, however, are always looking for elegant solutions to problems, and this is what has
happened with the ActiveX control project. Some people began using them as a substitute for
forms. This technique has some interesting benefits and overcomes some of the limitations dis-
cussed earlier. The essence of the approach is to design an ActiveX control exactly as you
would a form. Standard controls from the VB toolbox are arranged on the control designer to
form the interface. Figure 12.4 shows a typical ActiveX control project in Visual Basic.
Normally when you build an ActiveX control project, you have to be concerned about coding a
number of required behaviors. This means establishing an icon for the toolbox, creating an
about box, and dealing with property persistence. None of this is required when you want to
use an ActiveX control as a form. All you have to do is code the control just like a form. You
can, for example, call a COM+ component from within the control to retrieve XML data and
display it in a grid. After the control is finished and compiled, you can use it in an application.
Using the control is accomplished by dynamically loading the control at runtime. Visual Basic
can load any ActiveX control at runtime using the control’s programmatic identifier (ProgID).
This is accomplished using the Controls collection’s Add method. This method’sargument is
the ProgID of the control to load and a name for the new control. The following code loads a
button dynamically and names it Button1:
Controls.Add “VB.CommandButton”, “Button1”
COM+ and Win32
321
CHAPTER 12

12

COM+ AND
WIN32
FIGURE 12.4
ActiveX control projects can be designed like a form.

After the control is loaded, it becomes part of the Controls collection for the parent form and
you can then access the properties and methods of the control in code. Because loading the
control doesn’t cause it to be visible, you could use the following code to display the loaded
control:
Controls(“Button1”).Visible = True

Using this technique, you can load any control including the ActiveX controls you build in
Visual Basic. All you need to know is the ProgID of the control. The result of this design is
that your front end can now be constructed of a single form that acts like a browser. The form
can load the ActiveX controls you build similar to the way a Web browser loads pages.
The immediate benefit of this design is that you can package your ActiveX controls in separate
projects rather than put them all in one executable. Historically, developers placed all their VB
forms in one large executable, resulting in huge, hard-to-maintain projects. This new technique
parallels Web development, where each page can be modified individually without affecting
the rest of the project.

Sinking Events
When you use dynamically loaded ActiveX controls, you might want to be able to trap events
at the form level that occur within the control. Since the control was loaded dynamically, you
User Services
322
PART IV

have no real way to know what events are supplied by the control. You can overcome this limi-
tation by using the VBControlExtender object, which allows the establishment of a generic
event handler for any dynamically loaded control. To use this object, you first declare it
WithEvents:

Private WithEvents objEventHandler As VBControlExtender

After the variable is declared, you can set the instance returned by the Add method to this
object. When the object reference is set, the VBControlExtender will receive all the events
generated by the control. The following code shows how this is done:
Set objEventHandler = Controls.Add(“MyProject.MyControl”, “Control1”)
Private Sub objEventHandler_ObjectEvent(Info As EventInfo)
MsgBox Info.Name
End Sub

The Info object is returned whenever any event occurs in the control and it contains both the
fired event’s name and any parameters it passed. The control events are excellent for tracking
the application’s workflow and they can be used to determine the next control to load, for
example.

Limitations
When using this technique, keep in mind several limitations:
• The dynamic load is a late-bound process therefore the controls will load slower than if
they are compiled as part of the project.
• If you use any controls that require a license, it will have to be added to the Licenses
collection before loading the control.
• The VBControlExtender won’t work with intrinsic VB controls such as CommandButton
and TextBox. Keep these issues in mind so you can use this technique to create an appli-
cation that’s easier to design and maintain.

QUICK CHECK 12.3

Loading ActiveX Controls


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 12\Quick Check 12-3. This directory contains a partially complete
project you can use to dynamically load ActiveX controls.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 12-3. Copy the contents from the CD-ROM directory into this new
directory.
COM+ and Win32
323
CHAPTER 12

3. Open the project group named ax.vbg. This project contains an ActiveX DLL project, a
Standard EXE project, and an ActiveX control project.
4. The ActiveX DLL project is a COM+ component that reads data from the pubs database
and returns it as XML. In the Titles class, you need to change the connection string for
the GetAuthors and GetTitles procedures to match your configuration.
5. The ActiveX control project contains two controls that function like Web pages for the
application. The first control, named QUERY, is used to return all the author names and
display them in a list. The RESULTS control is then loaded to show the titles written by
the selected author. Figure 12.5 shows the controls in Visual Basic. 12

COM+ AND
WIN32
FIGURE 12.5
Design ActiveX control projects as you would design Web pages.

6. The Standard EXE project is used simply to load the ActiveX controls and receive
events. The events generated by the controls are navigation events. This technique is sim-
ilar to the use of anchor tags on a Web page.
7. Compile the project group.
8. In the Component Service explorer, create a new COM+ application and name it
ActiveX Controls. Install only the data component into the COM+ application. Don’t
install the executable or the controls in the COM+ application.
9. Run the application by double-clicking the file axclient.exe. This will cause the form to
load the author list that the control retrieves from the data component (see Figure 12.6).
User Services
324
PART IV

FIGURE 12.6
The first control shows a list of authors.

10. After the list of authors appears, you can double-click any name to see a list of titles for
that author (see Figure 12.7). The form knows to load the next page because the double-
click fires a custom event called Navigate. When you see the results in the second con-
trol, you can click the Back button to navigate back to the list and try another name.

FIGURE 12.7
The second control shows a list of books.

HTA Pages
Throughout the book, we have used a special Web page hybrid as a simple way to create test
harnesses for our exercises. This special file is known as an HTML Application (HTA) file and
is similar to an .htm file in that it’s written using standard HTML. However, HTA is unique
because it runs inside a standard window and not a browser and it is a trusted application. This
means that you can call any COM+ component or use any ActiveX control without limitation.
In the following sections, I go a little deeper into the HTA file and present some detail regard-
ing its capabilities.
COM+ and Win32
325
CHAPTER 12

HTA Functionality
At the highest level, HTA applications are simple to build because you need to build only a
standard Web page and give it an .hta extension. You’ve seen this technique many times
throughout the book. However, HTA files have some specific functionality that you will want
to use when basing a complete solution on this technology.
When designing an HTA, you will want to control several aspects of the application’s behavior.
Controlling appearance and behavior is accomplished through the use of the <HTA:
APPLICATION> tag, which allows you to specify several attributes for the HTA file. This tag is
placed directly in the HTML, but must reside between the <HEAD></HEAD> tags. Like all tags, 12
this tag can be named using the ID attribute. The following code shows how to use the
<HTA:APPLICATION> tag to define several attributes of the application:

COM+ AND
WIN32
<HEAD>
<TITLE>My First HTA Application</TITLE>
<HTA:APPLICATION ID=”MyHTA”
APPLICATIONNAME=”Test”
BORDER=”none”
CAPTION=”no”
ICON=”cdrom.ico”
SHOWINTASKBAR=”no”
SINGLEINSTANCE=”yes”
SYSMENU=”no”
WINDOWSTATE=”maximize”
>
</HEAD>

This code names the application Test and shows no border or title bar on the window. An icon
is defined for the application and several window behavior features are declared. The
<HTA:APPLICATION> tag defines a number of properties, as described in Table 12.1.

TABLE 12.1 HTA Attributes


Attribute Description
ApplicationName The application’s name within the operating system.
Border The type of window border with these possible values: thick (the
default), dialog, none, and thin.
BorderStyle The look of the window border with these possible values : normal
(the default), complex, raised, static, and sunken.
Caption Determines if the window has a title bar. Possible values are yes (the
default) and no.
CommandLine Returns command-line parameters used when the application was
launched.
User Services
326
PART IV

TABLE 12.1 Continued


Attribute Description
Icon The application’s icon.
MaximizeButton Determines if the window has a maximize button. Possible values
are yes (the default) and no.
MinimizeButton Determines if the window has a minimize button. Possible values are
yes (the default) and no.
ShowInTaskBar Determines if the application appears in the taskbar. Possible values
are yes (the default) and no.
SingleInstance Determines if more than one copy of the file can run. Possible values
are yes (the default) and no.
SysMenu Determines if the window has a system menu. Possible values are
yes (the default) and no.
Version The application’s version number.
WindowState Sets the size of the window. Possible values are normal (the default),
minimize, and maximize.

Deployment
After you create an HTA application, you have several choices for deploying the application.
HTA files can be deployed using a Web server just like any other HTML page or they can be
deployed in a package like a Win32 application. (Or, you can choose to use a combination of
the two approaches.)
When you choose to deploy the HTA from a Web server, you will be prompted with a dialog
asking to open or save the file. If the HTA file is opened, it simply runs and then downloads
any other components called for in the application. ActiveX controls, images, and style sheets
are all available to the downloaded HTA. Figure 12.8 shows the results of clicking an anchor
tag that references an HTA file.
When you choose to deploy the HTA in a package, you must create a setup and distribution for
the application. This is the traditional client installation process that you would perform when
deploying any “fat client” application. The advantage of this approach is that the HTA func-
tions like any client application. You can put icons on the desktop of items in the Start menu.
Users also don’t have to see the download dialog associated with the Web deployment method.
As a final approach, you might consider a combination of Web and package. Clients could save
the HTA file rather than run it directly from the Web. This would prevent having to download
the application each time while still making Web resources available to the application.
COM+ and Win32
327
CHAPTER 12

12
FIGURE 12.8

COM+ AND
HTA files can be run directly from the server.

WIN32
EXERCISE 12.1

Building a State Layer


This exercise creates an application that uses many of the principles described in this chapter.
You will be required to create stored procedures, classes, components, and a front end. This
application also uses some simple conflict resolution techniques.

Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
12\Exercise 12-1. This directory contains a partially complete project.

Step 2
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
12-1. Copy the contents from the CD-ROM directory into this new directory.

Step 3
In the SQL Server program group, start the Query Analyzer. Log in to SQL Server and select
the pubs database. This application uses four stored procedures to read author data from the
pubs database. These stored procedures are created by running a script. In the Query Analyzer,
locate the file procedures.sql in your exercise directory. Open the script and run it to create
the four stored procedures in the pubs database.

Step 4
Start Visual Basic. Open the project group named state.vbg. In the Project Explorer, you will
see several different projects representing interfaces, components, and the user services.
User Services
328
PART IV

Step 5
This project has a model associated with it in the file authors.mdl. You can use this model
diagram to help understand the architecture of the application. Figure 12.9 shows the diagram.

FIGURE 12.9
This diagram shows the application model.

Step 6
Examine the application model. Locate the component named AuthorStub. This is the only
component that runs under COM+ in this application. AuthorStub runs one of the four stored
procedures based on an enumerated type. It then creates a disconnected recordset that’s
returned to the user services layer. The AuthorStub class implements an interface called IStub,
which is an example of a standard you might use.

Step 7
The user services receives the disconnected recordset into the Proxy class. This class takes the
disconnected recordset and generates a custom collection. The Proxy object implements the
IProxy interface.

Step 8
In this application, we build a complete custom collection to manage the returned data. This is
the most complex way to maintain state, as we don’t use any type of data binding in this layer.
COM+ and Win32
329
CHAPTER 12

The collection contains instances of the Author class that represent information returned by the
stored procedures. Both the Authors collection and the contained class Author implement
interfaces defining their behavior.

Step 9
After you are satisfied that you understand the architecture of the exercise application, close
the Visual Modeler and return to Visual Basic.
The Business Services Layer
Step 10 12
In the Project Explorer, locate the project named BusinessStub. This is the COM+ component.

COM+ AND
In this project, locate and open the AuthorStub class that contains two simple methods for

WIN32
reading and writing data: Query and SubmitChanges. This component is more coarse than we
would create for a complete application because it contains code to directly access the data-
base, even though it’s officially in the business services layer. Nonetheless, the principles are
the same.

Step 11
The Query method runs a stored procedure and returns a disconnected recordset. The selected
stored procedure is based on an enumeration named QueryTypeEnum located in the
[General][Declarations] section.

Step 12
To update the database, pass the disconnected recordset back to the business services layer
through the Update method. This method attempts a batch update and returns a Boolean value
indicating success or failure. Conflicts aren’t resolved. Instead, any failure results in a refresh
of the data by the client.

NOTE
The connection string defined in this class might have to be modified for your config-
uration.

The User Services Layer


Step 13
The user services layer connects to the business services through the Proxy class. Locate the
Proxy class in the UserState project. Open the code window for this class. This class contains
functions that create items for the Authors collection or read the collection and build a record-
set for update.
User Services
330
PART IV

Step 14
The Populate function fills the Authors collection from a recordset passed in by the business
services layer. The collection is populated by calling the Add method of the collection for each
record in the recordset.

Step 15
The Update function reads all the entries in the collection and updates a recordset that is then
passed to the business services layer for updating.

Step 16
After you finish reviewing code, the application is complete. Compile the entire project group.

Step 17
In the Component Services explorer, create a new application named Authors. Install the Stub
component in the COM+ application.

Step 18
The application is run by starting the userdisplay.exe file that runs the front end and starts
up the business object. In the front end, you can try the various queries as well as edit data.
Figure 12.10 shows the front end for the application.

FIGURE 12.10
This is the front end for the application.
Integrating COM+ with CHAPTER

13
Groupware

IN THIS CHAPTER
• Integrating Exchange 2000 Server with
COM+ 332

• Integrating Microsoft Outlook 2000 with


COM+ 338

• Integrating Digital Dashboards with


COM+ 348
User Services
332
PART IV

In today’s business environment, knowledge workers are increasingly separated by time and
distance. Collaboration defines a set of applications that allow these separated workers to com-
municate and work as a team. Many forms of collaboration are available from a simple tool,
such as email, to a complex custom application. This chapter focuses on two products that
form the foundation for collaboration applications with COM+ technology: Microsoft
Exchange 2000 Server and Microsoft Outlook 2000.

Integrating Exchange 2000 Server with COM+


Microsoft Exchange 2000 Server ships with a host of tools and features that support collaboration.
Out of the box, Exchange provides its classic features such as messaging and personal informa-
tion management. With a little extra work, however, you can set up chat and instant messaging.
Exchange supports a number of different object models that allow access to data and workflow.

Understanding Web Storage


From a COM+ developer’s perspective, understanding Exchange begins with understanding the
Web storage system. Web storage, new in Exchange 2000, represents a collaboration data store
that you can use in your COM+ applications. Think of the Web store as a database that holds
unstructured data. In its simplest form, Web storage is a substitute for the old Exchange infor-
mation store. In this database, you will find email messages, contacts, and scheduling informa-
tion. However, Web storage can store more than just typical Exchange data. In fact, you can
store almost anything in it. This means, for example, that you can store various documents,
search them, and query them just like a structured database. What’s more, Web storage is
accessible through various interfaces such as ADO or the Web browser.
When you first install Exchange, Web storage is set up by default. In many ways, you can
think of Web storage as a combination of a file system, Web services, and information store.
You can, for example, view the Web storage structure directly in the file explorer because a
new drive is established explicitly for Web storage during the installation process. Figure 13.1
shows the Web storage structure in the file explorer.
The Exchange drive is also set up to be a virtual directory. If you examine the directories
defined in the Internet Services Manager, you will find that the alias for the root of the new
drive is \Exchange. This means that you can access the Web store directly from a browser by
typing in a URL for the server, followed by the virtual directory, as shown here:
http://scotwin2k/Exchange

When you access Web storage through the browser, Exchange automatically generates an
appropriate set of Web pages for the data. This service, known as Outlook Web Access, is an
improvement over previous versions of Exchange in which Web access was treated as an after-
thought. In Exchange 2000, Web access is fundamentally no different from file or Outlook
access to the store. Figure 13.2 shows Web storage accessed through the browser.
Integrating COM+ with Groupware
333
CHAPTER 13

13
FIGURE 13.1
Web storage is structured similar to a file system.

COM+ WITH
GROUPWARE
INTEGRATING

FIGURE 13.2
Web storage is accessible across the Internet.
User Services
334
PART IV

In addition to file and Internet access, you will be most interested in programmatic access to
the Web store. Programmatic access allows you to treat the Web store as a database and pro-
vides a mechanism for you to create a data services layer based on COM+ technology.
Programmatic access is achieved through two sets of objects: the ActiveX Data Objects (ADO)
and the Collaboration Data Objects (CDO).

ActiveX Data Objects: Accessing Web Stores


With the release of ADO 2.5, Microsoft introduced two new objects to the ADO model: Stream
and Record. Throughout this book, we have used the Stream object extensively to pass XML
strings in our applications. Now we will investigate the Record object.
The Record object was created to access unstructured data. Because unstructured data can’t be
grouped neatly into a tabular format, it can’t be accessed as a recordset. Therefore, it must be
accessed one item at a time. The Record object provides a mechanism for accessing the
unstructured data in the Web store.
To connect to an item in the Web store, you must create an instance of the Record object and
pass it the appropriate connection string. The Record object uses the OLEDB provider for
exchange (ExOLEDB); however, you don’t have to explicitly name this provider in the connec-
tion string because it’s used by default. Instead, all you have to do is provide the path to the item
you want to open. The connection string is in the form of a URL using the file:// designator.
In the Web store, private mailboxes are kept under the /MBX directory, whereas public folders
live in a directory by the same name. Both the /MBX and /Public Folders directories are
under a parent directory with the same name as the domain under which Exchange is running.
The virtual directory named backofficestorage identifies the root of the drive. You can see
the structure clearly by examining the Web store in the file explorer. The following code
accesses a single contact record in my mailbox for a person named John Q. Public:
Dim objRecord As ADODB.Record
Dim strURL As String
strURL = _
“file://./backofficestorage/dc.local/MBX/SCOTH/Contacts/John Q Public.eml”
Set objRecord = New ADODB.Record
objRecord.Open strURL

Once you have access to an individual record, you can read any of its properties. All the item’s
properties are contained in the Fields collection. Looping through this collection will generate
all the properties and values for the item. If you display these properties, you are likely to
experience a serious case of head scratching because the names of the properties are strange, to
say the least. The property names are based on a series of uniform resource identifier (URI)
namespaces. The complete list of properties is well beyond this discussion, but you can access
Integrating COM+ with Groupware
335
CHAPTER 13

them in the MSDN Library under the path Platform SDK, Messaging and Collaboration
Services, Microsoft Exchange 2000 Server, Reference, Web Store, Web Store Schema.
After you have access to the properties list, you can use it to create queries against the Web
store by using a Recordset object. Although the data in the Web store is unsuited for contain-
ment within a recordset, you can still use a Recordset object to return the properties that meet
your search criteria. After you identify items in the Web store that meet a criteria, you can use
the Record object to access the item directly.
The query language used by ADO to access the Web store is a custom language loosely based
on Structured Query Language (SQL). It uses familiar statements such as SELECT and WHERE.
However, similar to using the properties themselves, creating a query based on URI name-
spaces requires the constant presence of the MSDN Library. The code in Listing 13.1 shows a
query that returns all the contacts in a folder.

LISTING 13.1 Querying the Web Store


Dim objConnection As ADODB.Connection
Dim objRecordset As ADODB.Recordset
13
Set objConnection = New ADODB.Connection

COM+ WITH
Set objRecordset = New ADODB.Recordset

GROUPWARE
INTEGRATING
strConnect = “file://./backofficestorage/dc.local/MBX/SCOTH/Contacts”
objConnection.Provider = “ExOLEDB.DataSource.1”
objConnection.Open strConnect

strSQL = “select “
strSQL = strSQL & Chr$(34) & “DAV:displayname” & Chr$(34)
strSQL = strSQL & “ from scope (‘shallow traversal of “
strSQL = strSQL & Chr$(34) & strConnect & Chr$(34) & “‘) “
strSQL = strSQL & “ORDER BY “ & Chr$(34) & “DAV:displayname” & Chr$(34)

objRecordset.Open strSQL,objConnection

objRecordset.MoveFirst

Do While Not objRecordset.EOF

MsgBox objRecordset.Fields(“DAV:displayname”).Value
objRecordset.MoveNext

Loop
User Services
336
PART IV

The code that generates the query in Listing 13.1 can certainly be confusing. Because the
query string has a number of quotes in it, I have substituted the Chr$() function. When the
query is evaluated, it actually appears as follows:
Select “DAV:displayname”
From Scope(‘Shallow Traversal of
“file://./backofficestorage/dc.local/MBX/SCOTH/Contacts” ‘)
Order By “DAV:displayname”

The SELECT clause is similar to a SQL statement. It lists the properties you want to return from
the query. The FROM SCOPE clause can be though of as a reference to a table in a database. It
refers to the root of where the search will begin. If you specify a “Shallow Traversal”, the
search will be limited to the exact folder you specify. If, on the other hand, you specify a
“Deep Traversal”, subfolders will be included in the search. The ORDER BY clause then
arranges the results alphabetically by name.

Collaboration Data: Using Contact and Message Objects


Although ADO treats the Web store like a database, it’s quite often too raw for our business
applications. Rather than deal directly with URI namespace properties, we would often prefer
to work directly with contact and message objects. The Collaboration Data Objects (CDO)
provides an abstraction level appropriate for business applications.
CDO is an umbrella term that hangs over a number of different object models in Windows
2000. If you’re using Microsoft Exchange 2000 directly, you might use the CDO for the
Exchange 2000 object model. This model is based on Internet standards unlike other versions
of CDO that provide object access only to the Exchange information store. Client machines
that want to take advantage of collaboration use CDO for Windows 2000. This object model
is the latest version of the model that used to be called CDO for Windows NT. Microsoft has
also provided a model for performing administrative tasks known as CDO for Exchange
Management and a model for workflow application called CDO for Workflow.
Using CDO can be extremely easy. Sending an email message, for example, requires just a few
lines of code. In fact, we quietly used this concept in Chapter 9, “COM+ Business Features,” to
build an email component for our exercises. The following code creates a Message object in
CDO and uses it to send email:
Dim objMessage As CDO.Message
Set objMessage = New CDO.Message
Integrating COM+ with Groupware
337
CHAPTER 13

With objMessage
.To = “SCOTH”
.From = “JOHNQ”
.Subject = “CDO is easy”
.TextBody = “Here is a new message.”
.Send
End With

QUICK CHECK 13.1

Accessing Web Storage


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 13\Quick Check 13-1. This directory contains a partially complete
project you can use to query the Exchange Web store.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 13-1. Copy the contents from the CD-ROM directory into this new
directory. 13
3. Open the project group named cdoxml.vbg. This project contains a single class that will

COM+ WITH
GROUPWARE
INTEGRATING
query any folder in the Web store. Examine the code and note that the search directory is
determined by an object construction string.
4. Compile the project into an ActiveX DLL.
5. In the Component Services explorer, create a new COM+ application named Web
Storage. Install the compiled component into the new COM+ application.
6. In the Component Services explorer, open the property sheet for the Engine class.
Because this class uses construction, you will have to enable object construction on the
Activation tab. You must also enter a valid connection string for one of the folders in
Exchange (for example,
“file://./backofficestorage/dc.local/MBX/SCOTH/Contacts”).

7. Start a new project in Visual InterDev. Import the files default.asp and contents.xsl
into the new project.
8. The COM+ component returns the contents of the folder as XML which is then dis-
played. Open the page default.asp in the browser. The contents of the folder designated
in the construction string will be displayed. Figure 13.3 shows the results.
User Services
338
PART IV

FIGURE 13.3
Exchange folder contents are displayed in a table.

Integrating Microsoft Outlook 2000 with COM+


Microsoft Outlook 2000 is a powerful personal information manager (PIM) that you can easily
customize to create collaborative applications. You can use Outlook’s built-in features, includ-
ing contact management, schedule management, and email facilities, to provide collaboration
and workflow features while simultaneously interacting with COM+ components to provide
sophisticated transactional capabilities.
Microsoft Outlook provides a large number of customizable components that you can modify
without ever writing a single line of code. By customizing these components, you can quickly
create new data sets or even completely new applications. Customizable components in
Outlook include data views and forms:
• Data views are presentations of data in a grid format, the default data presentation style
in Outlook.
• Outlook forms are tabbed dialogs that contain more information than is normally found
in a view. Outlook forms are displayed when adding or editing a record. A single form
represents one record in an Outlook folder.
Users can customize Outlook views and forms at any time. Views can be customized by adding
or removing fields from the view. This can be accomplished by selecting Current View and
then Define Views from the View menu. In the Define Views dialog (see Figure 13.4), you can
Integrating COM+ with Groupware
339
CHAPTER 13

select any of the views defined for the current folder. You can then add or remove fields from
the view. You can also set up sorts and filters for the view from this dialog.

FIGURE 13.4
Use the Define Views dialog to customize a view. 13
Forms can be customized in Outlook only when the form is visible. You can customize any visi-

COM+ WITH
GROUPWARE
INTEGRATING
ble form by selecting Forms and then Design This Form from the Tools menu. This action
places the form into design mode, where you can use a control toolbox (choose Control Toolbox
from the Form menu) and script editor (choose View Code from the Form menu) to completely
customize the form’s appearance and behavior. Figure 13.5 shows a form in design mode.

FIGURE 13.5
Forms can be customized through a toolbox and script editor.
User Services
340
PART IV

The Outlook Design Environment


Although Outlook allows a high degree of customization, serious application development will
require you to write code. You can programmatically control Outlook by writing directly to the
object model in Visual Basic or by customizing a form using VBScript. This latest version of
Outlook also supports VBA applications through a built-in design environment, accessed by
selecting Macro and then Visual Basic Editor from the Tools menu. Figure 13.6 shows the new
VBA editor.

FIGURE 13.6
VBA can be used to control Outlook 2000.

Although Visual Basic and VBA can both access the Outlook object model, applications are
typically created by writing VBScript in a script editor associated with an Outlook form. As we
know from using VBScript in products such as Internet Explorer or Internet Information
Server, it’s a fairly limited language that primarily offers simple structures and loops for the
purpose of communicating with COM objects. This is also true in Microsoft Outlook. You
won’t write a tremendous amount of code in VBScript, but you will call out to existing object
models to accomplish business functions.
When coding Outlook applications, you begin by writing code to the Outlook object model
itself. As with many Microsoft applications, Outlook is built on COM objects, which represent
everything from forms to email messages. By using the Outlook object model, you can manipu-
late form interfaces, create and send email, assign tasks, and interact with COM+ components.
Integrating COM+ with Groupware
341
CHAPTER 13

The Outlook object model is extensive, and a complete examination of all the objects is
beyond the scope of a single chapter. However, some objects are critical to those of you want-
ing to integrate with Outlook. When you first start to manipulate Outlook through the object
model, you will want to access controls on the form. The following sections describe the key
objects necessary to manipulate a form. Complete help on the Outlook object model is avail-
able from the Help menu in the Outlook script editor.

The Application Object


The top-level object in the Outlook model is the Application object, which represents the
entire Outlook application. It’s essentially the gateway to all the other objects in the model.
When accessed from VBScript within an Outlook form, you never have to explicitly create an
instance of the Application object—it’s available directly by name. However, the object can
also be created externally by Visual Basic code. This means that you can choose to either
manipulate the Outlook product from VBScript inside an Outlook form or externally through a
Visual Basic program. The following code could be used to create an instance of Outlook in a
Visual Basic program:
Dim MyApplication As Outlook.Application
Set MyApplication = CreateObject(“Outlook.Application”) 13
The Item Object

COM+ WITH
GROUPWARE
INTEGRATING
The workhorse of the object model is the Item object. This object represents the currently open
item in Outlook. This means that if you are running code within an email message form, Item
is the current email form. If the code is within a task, Item is the current task.
Item is the equivalent of the Form object in Visual Basic. In keeping with the similarity
between Items in Outlook and Forms in Visual Basic, Outlook Items are event driven and have
several predefined events associated with them. For example, when an Item is first opened, it
will fire the Open event. This event is the equivalent of a Visual Basic Form_Load event. You
can write code for this event directly in the Outlook script editor. Outlook will even prepare the
event handler for you when you select Event Handler from the script editor’s Script menu.
Unfortunately, Outlook’s debugging environment is considerably less robust than Visual
Basic’s, but you can easily leverage your knowledge of VB to write code in Outlook. Table
13.1 lists all the events supported by the Item object.

TABLE 13.1 Item Events


Event Description
Open Fires when an item is opened
Read Fires when an item is opened for editing
Write Fires when changes to an item are saved
User Services
342
PART IV

TABLE 13.1 Continued


Event Description
Close Fires when an item is closed
Send Fires when an item is sent
Reply Fires when a user replies to this item
ReplyAll Fires when a user replies to all recipients of this item
Forward Fires when this item is forwarded
PropertyChange Fires when a property of the item is changed
CustomPropertyChange Fires when a user-defined property is changed
CustomAction Fires when a user-defined action is executed

The Inspector Object


Whereas the Item object is similar to the Visual Basic form, the Inspector object has no real
parallel in Visual Basic. The Inspector object in Outlook represents the frame around the cur-
rent form. In this sense, the Inspector acts as a container object for all the tabs and controls
on the form. You can access the Inspector object for the current Item by calling the Item
object’s GetInspector method:
Set MyInspector = Item.GetInspector

The Page Object


The Page object in Outlook represents one page in the set of tabbed pages on the form. The
Page object acts as a container for all the controls on it. Accessing an individual page is done
by using the name of the page as it appears on the tab. All the pages that you’ve customized in
Outlook are members of the ModifiedFormPages collection. The following code shows how
you can gain a reference to a customized tab named Qualifications:
Set MyPage = _
Item.GetInspector.ModifiedFormPages(“Qualifications”)

Controls Objects
All the controls that you place on a customized page in Outlook are members of the Controls
collection. These controls can be accessed by name in the collection. The names of controls
can be set by simply right-clicking the control and selecting Advanced Properties. This gives
you a standard properties window where you can name a control. The following code shows
how you could access a textbox named TextBox1 that’s on a page named Page1:
Set MyPage = _
Item.GetInspector.ModifiedFormPages(“Page1”) _
.Controls(“TextBox1”).Text
Integrating COM+ with Groupware
343
CHAPTER 13

As with controls in Visual Basic, you can create event handlers for Outlook controls. The event
handlers generally take the same form as they do in VB. However, because the Outlook envi-
ronment is limited, the script editor won’t create event handlers for controls. Instead, you must
enter the event handler yourself. When doing this, simply follow the Visual Basic convention.

Coding Outlook Items


Along with directly manipulating controls on a form, you will want to use the Outlook object
model to create and manage Outlook Items. Using the model, you can create new mail items
and task items, locate folders, and send information. This will allow you to automate commu-
nication and tasking among several members of a team. Creating any item is accomplished
through the use of the Application object’s CreateItem method. When you use this method,
you specify an argument for it that indicates which item to create. The following code shows
how to create a new instance of a MailItem (that is, email message):
Set MyMessage = Application.CreateItem(0)

This code assumes that you are coding in VBScript in the script editor for an Outlook form.
Because Outlook uses VBScript, it doesn’t support named constants. Therefore, we have to use
the constant 0, which indicates that a new MailItem should be created. If you control the Outlook 13
model externally from Visual Basic, you can use the named constants found in the Outlook

COM+ WITH
GROUPWARE
INTEGRATING
object model. Table 13.2 lists the named constants for creating items and their associated enu-
merated values. Although you can create a new item of any type supported by Outlook, this chap-
ter focuses on several key items, including the MailItem, TaskItem, and ContactItem objects.

TABLE 13.2 Create Item Constants


Constant Value
olMailItem 0
olAppointmentItem 1
olContactItem 2
olTaskItem 3
olJournalItem 4
olNoteItem 5
olPostItem 6

The NameSpace Object


When working with Outlook Items, you will want to access the underlying data system that
stores the Items in folders. This underlying system, called the NameSpace object, acts as an
entry point to the folder system. By using the NameSpace object, you can access any folder
User Services
344
PART IV

under Outlook. This allows you to create new items for the folders. With this capability, you
can easily create new tasks, for example, and place them on a task list. The NameSpace object
is returned through the GetNameSpace method, which takes as an argument the data store you
want to return. Currently, only one data store is supported: MAPI. The following code returns
the MAPI NameSpace:
Set MyNameSpace = Application.GetNameSpace(“MAPI”)

The Folders Collection


Once you have access to the MAPI NameSpace, you will want to use it to locate folders in
Outlook. You can use the GetDefaultFolder method to return any of the default folders in
Outlook. Default folders refer to the set of folders associated with the client’s inbox.
GetDefaultFolder takes as an argument an integer constant that specifies what folder to
return. Table 13.3 lists the named constants and their values. The following code shows how to
return a reference to the default inbox:
Set MyInBox = MyNameSpace.GetDefaultFolder(6)

TABLE 13.3 Constants for the GetDefaultFolder Method


Constant Value
olFolderDeletedItems 3
olFolderOutbox 4
olFolderSentMail 5
olFolderInbox 6
olFolderCalendar 9
olFolderContacts 10
olFolderJournal 11
olFolderNotes 12
olFolderTasks 13

In addition to default folders, you can locate any folder in the list through the Folders collec-
tion. Each folder in the list also has a subsequent Folders collection. Suppose that you have a
PST file named My Projects and a folder in the PST file named Test Application. You can
locate the Test Application folder with the following code:
Set MyNameSpace = Application.GetNameSpace(“MAPI”)
Set MyPSTFolder = MyNameSpace.Folders(“My Projects”)
Set MyTestFolder = MyPSTFolder.Folders(“Test Application”)
Integrating COM+ with Groupware
345
CHAPTER 13

The TaskItem Object


The TaskItem object is one of several different items you can create with the Outlook object
model. This item is particularly useful in applications because it allows you to assign tasks to
members of a group. Assigning a task is accomplished by locating the folder in which you
want to add the new task, and then adding the TaskItem to the folder’s Items collection. The
following code locates the default Task folder and adds a new TaskItem:
‘Locate the Tasks Folder
Set MyTasks = MAPINameSpace.GetDefaultFolder(13)

‘Add a new task


Set NewTask = MyTasks.Items.Add(“IPM.Task”)
NewTask.Categories = “TO DO”
NewTask.Subject = “Web Page Updates”
NewTask.Display

When you add any item to a folder, you specify the Message Class of the Item you want to
add. In the preceding code, you can see that the message class for a standard task is IPM.Task.
Every form you create has a message class, which is a combination of the default message
class and the name under which you publish the form. Thus, if you modify a standard task and 13
publish it as MyTask, the message class for the custom form will be IPM.Task.MyTask.

COM+ WITH
GROUPWARE
INTEGRATING
The ContactItem Object
The ContactItem object represents a new contact in Outlook. Contacts normally represent per-
sonal and business contacts, phone numbers, and addresses. However, they’re also useful for
creating applications that deal with information about people. We can use them to create
Outlook applications that handle customers, employers, or vendors. Contacts are added to fold-
ers in much the same way as tasks. Once a contact is added to a folder, you can set key infor-
mation, such as the name and address. The following code adds a new contact to the default
contacts folder and sets some information:
‘Locate the Contacts Folder
Set MyContacts = MAPINameSpace.GetDefaultFolder(10)

‘Add a new contact


Set NewContact = MyContacts.Items.Add(“IPM.Contact”)
NewContact.LastName = “Hillier”
NewContact.FirstName = “Scot”
NewContact.Save

The MailItem Object


The MailItem object represents an email message. By using the Outlook object model, you
can create new messages, edit their content, and send the messages to others. MailItem has
dozens of properties associated with it that allow you to completely manage the new message.
User Services
346
PART IV

When you create a MailItem, you can use the Subject and Body properties to edit the basic
message content. The Send method is used to send the message to a recipient.
Addressing the MailItem is done through the Recipients collection. When you add a recipient
to the Recipients collection, you can use any valid text that can be resolved by Exchange.
This includes, full names, usernames, and mail addresses. When you have added the appropri-
ate recipients to the collection, you can have Exchange resolve the addresses using the
Recipients collection’s ResolveAll method. The ResolveAll method returns True if all the
recipients were satisfactorily resolved. The following code creates a new MailItem, adds sev-
eral recipients, and sends the message:
Set NewMailItem = Application.CreateItem(0)

NewMailItem.Recipients.Add(“SCOTH”)
NewMailItem.Recipients.Add(“PATRICKB”)
NewMailItem.Recipients.Add(“GARYS”)

If NewMailItem.Recipients.ResolveAll Then
NewMailItem.Subject = “Test Mail Item”
NewMailItem.Body = “This is a test of the Outlook object model.”
NewMailItem.Send
Else
MsgBox “Sorry, all recipients were not rersolved!” _
End If

QUICK CHECK 13.2

Working with Outlook Items


1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 13\Quick Check 13-2. An Outlook Personal Folder (PST) file
within the directory contains a help desk application that submits help desk requests to a
common pool where technicians can pick up and accept assignments.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 13-2. Copy the contents from the CD-ROM directory into the new
directory you just created.
3. Start Microsoft Outlook. Open the file outlook.pst by selecting Open and then
Personal Folders from the File menu. You should see the Help Desk application in the
folder.
Integrating COM+ with Groupware
347
CHAPTER 13

4. Click the HelpDesk project in Outlook. This project folder was created based on the
mail items module. Applications based on the mail items module can act similar to news
groups in which people can post messages for others to read. In this application, we have
already defined part of a custom form for posting help desk requests. When forms are
defined in a folder, they are available under the Actions menu. Select New Helpdesk
Request from the Actions menu to view the form (see Figure 13.7).

13

COM+ WITH
GROUPWARE
INTEGRATING
FIGURE 13.7
This form is used to post help desk requests.

5. When the form is visible, enter design mode by selecting Form and then Design This
Form from the Tools menu. Now open the script editor for the form by selecting View
Code from the Form menu.
6. In the form, users can select a category for their request and type a description. When the
form is filled out, it’s sent with the Submit button. When the form is submitted, it’s
posted to the folder where it can be examined by all help desk technicians. A new mail
item also is sent to the general technical support mailbox announcing that a new request
has been placed in the queue. (You will want to change the mailbox for technical support
to match your configuration.)
7. Close the script editor and return to the form. Every Outlook form you customize will
actually have two different views: Compose and Read. The Compose page is the view of
the form when a user creates a new item. The Read page is the form view when a recipi-
ent opens the form. Switch the form to the read view by clicking the Edit Read Page but-
ton. Figure 13.8 shows the read view of the form.
User Services
348
PART IV

FIGURE 13.8
This view is seen by the recipient of the mail message.

8. When the help desk receives the request, the read page allows the desk to create a new
task item for the submitted request. The technician simply clicks the Create Task button
to create a new task in the default task folder and send an email confirmation to the orig-
inal sender of the request. Open the script editor and view the code to the click event of
the CreateTask button.
9. After the code is added, publish the form to the folder by selecting Forms and then
Publish Forms from the Tools menu. When the form is published, close the form.
10. Now you should be able to send a request. Open the form by selecting New Helpdesk
Request from the Action menu. Type a request and submit it. Locate the sent email mes-
sage and try accepting the task.

Integrating Digital Dashboards with COM+


Web portals are popular ways to organize information on the Internet. The value of a portal is
that you can customize it to show information that’s important to you. Portals act to sort and
filter the vast information on the Web. As information grows within an organization, compa-
nies can experience the same problems as Internet users. Information overload leads to
decreased productivity as everyone tries to wade through the piles of spreadsheets, emails,
and reports.
Outlook 2000 supports a new feature designed to create a corporate portal. Corporate portals
do for the company what Internet portals do for the consumer. Microsoft calls these portals
digital dashboards, customized views within Outlook based on Web pages. At their heart, they
Integrating COM+ with Groupware
349
CHAPTER 13

are simple to implement, but in practice, they can be powerful knowledge management solu-
tions. Figure 13.9 shows an example of a digital dashboard running in Outlook 2000.

13

COM+ WITH
GROUPWARE
INTEGRATING
FIGURE 13.9
Digital dashboards organize information.

Technically, digital dashboards are simple to create. Essentially, they are nothing more than a
Web page that provides links to critical applications and information. The Web page can then
serve as the starting point for any folder or as a substitute for the Outlook Today page. To
make them even easier to build, Microsoft even provides a toolkit of controls known as the
Digital Dashboard Starter Kit. This toolkit gives you examples and ActiveX components that
perform common tasks such as displaying tasks and appointments.
Building a digital dashboard can be as simple as customizing one of the samples that comes
with the starter kit. These samples make use of the MS Investor Ticker for stock quotes and the
Microsoft Outlook View Control for displaying Outlook items. These controls can easily be
added to the Visual InterDev toolbox, as shown in Figure 13.10.
After you create the page, you can assign it to any folder or make it the default for Outlook
Today. If you installed the starter kit, you will find a new entry on the Tools menu to set a new
Outlook today page. After you display the simple information, you can go on to access your
COM+ components from the same page.
User Services
350
PART IV

FIGURE 13.10
ActiveX controls make Digital Dashboards easy to build.

EXERCISE 13.1

Building a Corporate Portal


This exercise uses COM+ components and a Web page to create a simple corporate portal.
Although you don’t need the Digital Dashboard Starter Kit to build this exercise, you can cer-
tainly use the kit later to enhance the project.
Building the COM+ Components
Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\
Chapter 13\Exercise 13-1. This directory contains COM+ components for use with the cor-
porate portal.

Step 2
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
13-1. Copy the contents from the CD-ROM directory into this new directory.
Integrating COM+ with Groupware
351
CHAPTER 13

Step 3
Open the project dashboard.vbp. This project contains two COM+ components. The Exchange
class returns items from the Exchange Web store. The Pubs class runs a query on the pubs
database that returns book titles. These components show the vastly different types of informa-
tion you can include in a corporate portal.

Step 4
In the Pubs class, modify the connection string to access the pubs database for your configura-
tion.

Step 5
In the Exchange class, modify the connection string to access your email inbox.

Step 6
Compile the project into an ActiveX DLL.

Step 7
Using the Component Services Explorer, create a new COM+ application named Dashboard.
Install the Exchange and Pubs classes in the new application. 13
Using the New Page

COM+ WITH
GROUPWARE
INTEGRATING
Step 8
If you don’t have the Digital Dashboard Starter Kit, you will have to change the Outlook Today
page by hand in the system Registry. Start the Registry Editor and find the following key:
HKEY_CURRENT_USER\Software\Microsoft\Office\9.0\Outlook\Today

Create a new String value and name it URL. Set the Value to the path for dashboard.htm.
This is the file we will use for our corporate portal.

Step 9
Start Outlook and look at the new page. Figure 13.11 shows the finished page.
User Services
352
PART IV

FIGURE 13.11
A corporate portal can combine many types of information.
Debugging and Deploying CHAPTER

14
COM+ Applications

IN THIS CHAPTER
• Debugging COM+ Components 354

• Deploying COM+ Applications 356

• Analyzing COM+ Applications 363


User Services
354
PART IV

When you create enterprise applications with COM+, you encounter a whole new level of
troubleshooting issues. You have to deal not only with the validity of your code solution, but
also with issues of network traffic and bottlenecks. As Windows DNA development becomes
more about Internet applications, you have the additional burden of ensuring that your Web site
stands up under the load. This chapter discusses debugging techniques, site analysis, and the
distributions of components for your solutions.

Debugging COM+ Components


Debugging COM+ components isn’t as simple as setting break points and running your appli-
cation. Whether the component is intended for use by a Visual Basic front end or an Active
Server Page, setting up debugging requires special attention. The following sections cover the
essential process for debugging COM+ components in Visual Basic and Visual InterDev.

Debugging in Visual Basic


To take advantage of COM+ debugging features in Visual Basic 6.0, you must establish very
specific conditions:
• Use the MTSTransactionMode property to identify your project as a COM+ component
by changing the value to anything other than NotAnMTSObject.
• Compile the COM+ component as an ActiveX DLL and install it in a COM+ application.
• Set the version compatibility to Binary Compatibility for the ActiveX DLL project in
Visual Basic (see Figure 14.1).
When you meet all these conditions, you can set breakpoints in the ActiveX DLL project and
debug your COM+ components in line.

FIGURE 14.1
Set binary compatibility to help debug components.
Debugging and Deploying COM+ Applications
355
CHAPTER 14

Debugging in line is useful for stepping through your code, but I often find that I also need to
collect error information at runtime. For this reason, I build logging into every method. It’s
simple enough to use the App object in your error handler to create a local log file for your
component, and I have found this log to be essential in identifying problems that transcend a
single component. The following code should be familiar from earlier exercises:
‘Log errors
Debug.Print Err.Description
App.StartLogging App.Path & “\error.log”, vbLogToFile
App.LogEvent Err.Description, vbLogEventTypeError

In some projects, you might want to run the same component as both a configured and non-
configured component. If you rely on implicit activation and deactivation, this isn’t an issue
because your project won’t have any context code in it. In fact, this is one of the major advan-
tages of relying on the automatic aspects of COM+. However, if you choose to use context
code, it will cause errors when your component isn’t inside a COM+ application.
One simple solution to the problem is to check and see if the context exists. In this technique,
you simply check to see if the context is nothing before calling SetComplete or SetAbort. The
following code shows how this is done:
If Not (objContext Is Nothing) Then objContext.SetComplete

Although checking the context instance will allow you to run COM+ code in the VB environ-
ment, purists would argue against a technique that codes for more than one target platform.
The alternative to this approach is to use conditional compilation. With conditional compila-
tion, you can hide the context code when debugging. For example, the following code hides
the SetComplete call when the debugging flag is False:
#Const COM+ = True
14

DEPLOYING COM+
#If COM+ Then

DEBUGGING AND
APPLICATIONS
objContext.SetComplete
#End If

Debugging in Visual InterDev


Debugging a COM+ application called from within Visual InterDev presents some special chal-
lenges. This is because Visual InterDev attempts to call into your running copy of Visual Basic
through the anonymous access normally granted a Web user. If you create a simple ActiveX
DLL and call it from an ASP page, you will be denied access, as shown in Figure 14.2.
To overcome this limitation, you must change the directory security settings for the project. In
the Internet Services Manager, uncheck the Anonymous Access box. This will force your cre-
dentials to be authenticated when the component is called, which will allow you to run the
code inside Visual Basic. Figure 14.3 shows the security properties inside the Internet Service
Manager.
User Services
356
PART IV

FIGURE 14.2
ASP can’t create components running in Visual Basic.

FIGURE 14.3
Disable anonymous access to debug components from Visual InterDev.

Deploying COM+ Applications


Because network connectivity issues can cause problems during the debugging process, I have
always found it easier to develop COM+ applications on a single machine. However, after you
debug the components in your COM+ application, you will need to deploy them to machines
on the enterprise. Deploying a COM+ application is significantly more complex than a tradi-
tional application and requires some thought and planning to be successful.
Debugging and Deploying COM+ Applications
357
CHAPTER 14

Deploying Data Services


Deploying the data services layer means creating SQL Server database structures, establishing
permissions, and connecting remote servers. The simplest way to begin this deployment is to
create a database script from your test installation of SQL Server. This script can then be used
to generate the new database structure on another SQL Server installation. The script you cre-
ate might contain appropriate security information, or you might have to modify the settings.
In any case, be sure to establish a single Windows 2000 account if you intend to use connec-
tion pooling. Figure 14.4 shows the SQL Server script generation dialog.

FIGURE 14.4
Generate SQL Scripts to deploy the database structure.

Deploying Business Services


14
Deploying the business services layer is all about deploying COM+ components. Although

DEPLOYING COM+
DEBUGGING AND
other layers—most notably data services—can contain COM+ components, the mechanics for

APPLICATIONS
deploying the components don’t change. Therefore, we will cover all the information in this
section.
If you’ve built your distributed application on a single machine or in a separate testing environ-
ment, you already have COM+ components installed and working. Deploying these compo-
nents is a matter of moving them from one installation of COM+ to another. The simplest way
to move an application is to create a Microsoft Installer (MSI) file. MSI files are installation
files that work with the Microsoft Installer system. The Microsoft Installer is built into
Windows 2000 and makes distributed application deployment much simpler than it was under
MTS. We’ll look at this system a little later in the chapter.
User Services
358
PART IV

Exporting an application is done by simply right-clicking the application of interest and select-
ing Export. When you select this menu, the COM+ Application Export Wizard starts (see
Figure 14.5). This wizard allows you to select a location for the MSI file you want to create.

FIGURE 14.5
Use this wizard to create exported MSI files.

Once a MSI file is created, you can take it to any COM+ installation and use it to create a new
application. You utilize the MSI file in the Application Install Wizard. Up to this point, we have
always selected the Create an Empty Package option on the wizard. When you import from a
MSI file, select the option Install Pre-built Package. The wizard will then let you browse for
MSI files to install. Figure 14.6 shows the select files dialog.

FIGURE 14.6
Use this dialog to import MSI files.
Debugging and Deploying COM+ Applications
359
CHAPTER 14

QUICK CHECK 14.1

Exporting Applications
1. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 14-1.

2. Start the Component Services explorer. Select any application that you have previously
installed. Right-click the application and select Export to start the wizard.
3. In the wizard, select to create a server application named quick check.msi. Place this
file in the directory you created earlier.
4. After the MSI file is exported, open the Windows File Explorer and examine the direc-
tory in which you created the MSI File. In the directory, you will find a MSI file as well
as a cabinet (.cab) file. These files are ready to use for installation on another machine.

Deploying User Services


If you intend to use Active Server Pages to call your COM+ components, your only issue will
be deploying the Web pages to the production server. However, you will want to be certain that
you evaluate the need to run your ASP pages in a separate memory space. All ASP pages ini-
tially run in the memory space of IIS, which is usually optimal, but if you have concerns about
your application misbehaving, you might want to isolate it.
If you will be using a more traditional front end for your application, you will have to create a
client setup. Creating the client setup requires that you build installations for the client inter-
face and an appropriate proxy for your COM+ application. Because the client and the COM+ 14
component won’t reside on the same machine, you must do some extra work to set up.

DEPLOYING COM+
DEBUGGING AND
APPLICATIONS
Creating a Proxy
A proxy setup is required for all distributed applications that have a rich client front end.
Creating the proxy normally involves a series of Registry entries and a type library for the tar-
get components. COM+ has significantly simplified this process, however, by making proxy
creation as simple as exporting an application.
To create a proxy setup for the client, you start the same way you did to export an application.
Right-click the application and select Export. In the same wizard that you used to create an
MSI file for a component, you can select to create a proxy setup instead. The MSI file created
for the proxy setup must be run on the client machine before a DCOM call to the target com-
ponent can succeed.
User Services
360
PART IV

When you create a proxy setup, the resulting MSI file contains information about the location
of the target component. By default, COM+ assumes that the component will reside on the
same server where you created the proxy setup. However, this often isn’t the case. You might,
for example, be building a proxy setup from a test server and deploying to a production envi-
ronment. To change the target server for the proxy setup, you use the property sheet for My
Computer. In this dialog box, you can enter a new remote server name to be used when creat-
ing proxy setups. Figure 14.7 shows where to enter the name of the target server.

FIGURE 14.7
You can change the remote server targeted by the proxy setup.

Creating a Client Setup


In addition to creating a proxy setup, you will also need to create a setup for the client soft-
ware. The setups you create for your client applications also need to be in the form of an MSI
file. To create these setups, you will need to build a new Visual Studio Installer project.
Visual Studio Installer projects are part of the Visual Studio suite. However, before you can use
this project type, you must install the Windows 2000 Developer Readiness Kit. This kit is an
add-on pack to Visual Studio that shipped when Windows 2000 went to market. It contains
documentation, logo requirements, and the Windows Installer. You can download the kit from
Microsoft’s Web site at
http://msdn.microsoft.com/vstudio/prodinfo/datasheet/winkit.asp

When you start a new Visual Studio Installer project, you are presented with a number of
options. One choice is to create a new Visual Basic Installer project. Figure 14.8 shows the
project dialog box for the Visual Studio Installer.
Debugging and Deploying COM+ Applications
361
CHAPTER 14

FIGURE 14.8
Select to create a setup for a Visual Basic project.

If you select this project type, you will then be prompted to locate the Visual Basic project file
(.vbp) for which you want to create a setup. The process of using the Visual Studio Installer to
create a setup for your Visual Basic project is just as straightforward as the older Package and
Deployment Wizard that ships with Visual Basic. The difference is that the Installer creates
MSI files, whereas the Package and Deployment Wizard uses .cab files. MSI files are compat-
ible with the Windows 2000 Installer, whereas .cab files are not.
When you create a new setup, the Visual Studio Installer project will automatically determine
your application’s dependencies. This means that files such as the Visual Basic runtime are
automatically added to the setup. When creating an MSI file specifically for a distributed appli-
cation, you must carefully examine the dependencies created by the Installer project because
the Installer will always want to distribute the actual component with your installation. To cor-
rect this problem, you must manually delete any dependencies linked to COM+ components.
You can then compensate for the missing dependency by installing the proxy setup. Exercise 14

DEPLOYING COM+
14.1 at the end of this chapter walks you through the process of creating a complete setup.

DEBUGGING AND
Group Policies APPLICATIONS
After you create a proxy setup and an application setup, you are left with two MSI files. Both
files must be installed on a client machine to run the distributed application. At this point, you
could simply install them by hand and your application will run. However, this would mean
that you have to install the files on every client machine. This is exactly why fat clients have
fallen out of favor.
The solution to the client distribution problem lies in the creation of a group policy. Group
policies allow you to specify that certain software should automatically be installed on a desig-
nated set of computers. Group policies are created and managed through the Active Directory
Users and Computers snap-in. If you start this snap-in, you can view the available group
User Services
362
PART IV

policies by right-clicking any domain, site, or organizational unit and selecting to view proper-
ties. In the properties dialog is a Group Policies tab (see Figure 14.9). Exercise 14.1 at the end
of this chapter walks you through the process of using a group policy to install new software.

FIGURE 14.9
Group policies can help deploy software on the network.

Deployment Checklist
Deploying application requires several steps, and it can be easy to forget all the required items.
The following is a checklist of items to perform during a COM+ deployment:
Data Services:
• Build SQL Scripts for database structures
• Create Windows 2000 and SQL Server accounts
• Enable the MSDTC service on all SQL Server installations
• Enable the RPC service on all SQL Server installations
Business Services:
• Build MSI files for components
• Ensure that roles are established with appropriate membership
• Ensure that package security is enabled where appropriate
• Turn on security for the system package
• Disable component editing and deletion
Debugging and Deploying COM+ Applications
363
CHAPTER 14

User Services:
• Run ASP applications in a separate memory space, if necessary
• Build MSI files for client proxy installations
• Build MSI files for front end
• Create a group policy to distribute the MSI files

Analyzing COM+ Applications


After you build your COM+ application, you will undoubtedly want to know how it performs.
Historically, it has been difficult for developers to realistically simulate large loads on distrib-
uted applications. In many cases, applications are simply deployed and the stress testing is
accomplished while the application is in actual use. The idea of stress testing has become
increasingly important as more and more distributed applications target the Internet.
Fortunately, we now have a tool that can help to determine if an application is ready for a large
load. This tool is known as the Web Application Stress tool (WAS).
WAS is a free tool that you can download from http://webtool.rte.microsoft.com. This
tool is designed to simulate large numbers of users making requests from your COM+ applica-
tion. The tool is intended to be used for COM+ applications that use Active Server Pages as the
front end. Figure 14.10 shows the WAS user interface.

14

DEPLOYING COM+
DEBUGGING AND
APPLICATIONS

FIGURE 14.10
WAS simulates multiple users stressing a Web site.

After downloading WAS, you simply install it on one or many client machines that can access
your Web site. The stress test is accomplished by automating client requests to the site, so you
User Services
364
PART IV

don’t want to run the test from the same machine where the Web site is located. If you install
and run WAS from the same machine where your Web server is running, the test results will be
meaningless.
Creating a test using WAS can be very easy. WAS has a simple interface that uses a script to
generate repeated calls to a Web site. You can program the scripts by hand, but it’s just as simple
to record a script using your browser. After the script is recorded, you can then set the site’s
stress level by adjusting the number of threads the client should use to make requests of the site.

The Testing Process


When you first start to use WAS, you might be confused as to the best way to test your site and
evaluate the results. In this section, I’ll discuss a basic testing process that you can use to quan-
titatively evaluate your application.
The primary measurement used to evaluate our application is MHz/Request/Second (MRS).
MRS is a standardized way to compare test results that you generate using WAS. MRS is a
measurement of how much effort your system processor has to put forth to respond to an
Active Server Page request from a client. The following shows the formula for MRS:
MRS = NSU/R
where,
N = # of processors
S = Speed of the processors (MHz)
U = Processor utilization (%)
R = Requests per second
MRS really isn’t intended as an absolute measurement, although any MRS under 10 will cer-
tainly indicate excellent performance. Instead, you should use MRS as a means of comparing
various solutions to see how they affect performance. Using this formula, if we had two
450MHz processors with an average processor utilization of 80 percent that could handle 100
ASP page requests each second, we could compute the MRS as follows:
MRS = (2)(450)(0.8)/100 = 7.2 MHz/Request/Second
WAS can help us determine MRS for any application by recording performance counters dur-
ing the test. After you record a script, you can then indicate which performance counters WAS
should collect from the target Web site. These performance counters can then be used to com-
pute MRS. Figure 14.11 shows the dialog for selecting performance counters in WAS.
Debugging and Deploying COM+ Applications
365
CHAPTER 14

FIGURE 14.11
Select performance counters to analyze your application.

WAS makes all the performance counters on the server available to your test. This alone can
make the choices confusing. Normally when we run a WAS test, we select at least the follow-
ing performance counters:
• Processor(_Total)\% Processor Time
• Active Server Pages\Requests/sec
• Active Server Pages\Requests Queued
• Web Server\Connection attempts/sec
After the counters are selected and the script is recorded, you set the stress level for the test. 14
The stress level is set by specifying the number of threads to run against the Web site. When

DEPLOYING COM+
DEBUGGING AND
specifying stress, begin with just one thread and work your way up slowly. For each run of

APPLICATIONS
WAS, examine the processor utilization (Processor(_Total)\% Processor Time), and the request
rate (Active Server Pages\Requests/sec). Continue to increase the stress on the system until the
processor utilization exceeds 85-90% or until the request rate drops significantly. Once either
situation occurs, you’ve exceeded your system’s performance peak. During the test, you must
also make sure that the processor utilization on the client stays below 80-85%, or the test may
be invalid. If the client processor is working too hard, add another client to the test and
decrease the number of threads for each client.
After collecting data, analyze your results. Before making any calculations, compare the
processor utilization to the queued request rate (Active Server Pages\Requests Queued). If the
processor utilization exceeds 85-90% before the queued request rate rises significantly, your
system is processor bound. If the queued request rate rises significantly while processor uti-
lization remains low, a COM+ component is likely causing a system bottleneck.
User Services
366
PART IV

For each run of WAS, you can now calculate MRS and use this number to compare solutions
to see if your system is ready for deployment. If you are processor bound, you might have to
add another server to the Web farm. If you are limited by a COM+ component, you might have
to redesign the component.

Assessing Performance
Throughout the time that I’ve been in the Visual Basic community, I’ve always been dismayed
by discussions of performance. Performance is a word used frequently to justify certain tech-
niques or architectures; however, I often find that this justification lacks any quantitative back-
ing. Someone will say, “Component A performs better than Component B.” I ask in return, “By
how much and under what conditions?” It seems that all discussions of performance are mysti-
cal and qualitative.
Let me put a stake in the ground right here. Performance is in your database. It always has
been and always will be. Any performance gains achieved through the use of a certain lan-
guage or architecture can easily and immediately be eclipsed by a poorly designed database
query. If you want your COM+ applications to perform, involve your database administrator
(DBA) early and often in your development efforts.
Throughout my system testing, nothing has affected the MSR rating more than the number of
records returned from a query. In fact, I could see a direct and significant correlation between
the size of the recordset returned and the MSR rating. This correlation was independent of the
complexities of the COM+ architecture. The following table shows the stress test results for a
single COM+ component called from an ASP page. This component did nothing except exe-
cute a query and return the results.

Records Returned MSR


25 20.8
150 130
5000 3500
Then I ran the same test against the completed project from Chapter 17. This project is much
more complex and involves many more COM+ components. It also uses a payload object that
performs several data transformations with ADO and MSXML. In a qualitative discussion of
performance, you might conclude that all this processing would affect the system, but the
results were nearly identical:

Records Returned MSR


25 20.8
150 125
5000 2500
Debugging and Deploying COM+ Applications
367
CHAPTER 14

The conclusion of this testing is that the size of the dataset returned eclipses everything when
it comes to performance. The complexity of the solution, number of components, and use of a
payload object were undetectable in the results. Therefore, the best investment any company
can make in performance is to hire the right DBA.
Having proven the importance of properly designed data access components, we can now
examine the relative performance of different architectures. In another set of experiments, I
tested several different architectures while holding the number of records returned to 25. These
tests examined ASP-only solutions, component-based solutions, and the completed project in
Chapter 17.
If your only interest is raw speed, the single best solution is to use only Active Server Pages. In
my tests, all-ASP solutions performed better than any other with an average MSR consistently
under 10. This argument favors using transactional Web pages and script-based classes.
Adding components to the solution resulted in some performance loss. When a single compo-
nent was used to encapsulate data access, the resulting MSR was 13. This means that VB com-
ponents perform worse than script; however, the relative magnitude isn’t significant when
compared to the effects of recordset size.
Testing the completed project from Chapter 17 showed some further performance loss. In this
case, I observed MSR values around 20. Strictly speaking, you can now make the statement
that all-ASP solutions perform twice as well as solutions based on XML and a Payload object,
but again, you would be ignoring that an MSR rating of 20 is still excellent.
The conclusion that we can draw from stress testing these architectures is that as we make an
application more maintainable through partitioning, we must pay for it with performance.
However, if we observe good design and pay careful attention to data access methods, we can
create easy-to-maintain applications that perform well. In all cases, you must commit to stress 14
testing your application before deployment to ensure that it will perform well.

DEPLOYING COM+
DEBUGGING AND
APPLICATIONS
Load Balancing
In a properly designed COM+ application, your system should never be bound by a compo-
nent. As I tested the applications from this book, I found that in all cases, the systems were
bound by the microprocessor. This means that the components efficiently move data, but the
hardware just doesn’t have enough horsepower to do any more work.
In the case in which you are bound by the processor, you will need to implement a Web farm
system based on Network Load Balancing (NLB). NLB is available from any Windows 2000
Advanced Server, but isn’t activated by default. You can activate NLB through the connection
properties associated with your network card. Figure 14.12 shows the property dialog where
you activate NLB.
User Services
368
PART IV

FIGURE 14.12
Network Load Balancing is activated through the connection properties.

When you set up NLB, you generally use two network cards: one for a dedicated Internet
Protocol (IP) address for the individual server, and one to use with the balancing cluster.
Servers that participate in a NLB cluster should have their dedicated IP address hard-coded as
opposed to using DHCP. Once the dedicated IP address is established, you can set properties
for the cluster. Checking the Network Load Balancing box will allow you to click the
Properties button and access the tabbed dialog for NLB.
Start with the Cluster Parameters tab (see Figure 14.13). In this tab, you set the Primary IP
Address to the address for the cluster. The Full Internet Name should be set to the cluster name
(for example, cluster.mydomain.com). The Full Internet Name must be registered with your
DNS service before load balancing will work.
The Host Parameters tab (see Figure 14.14) allows you to set a unique host ID for the server.
The lowest host ID in the NLB cluster is the player-coach. This server receives all requests and
directs them to other members of the cluster. IDs should be used sequentially from 1 to the
number of machines in the cluster.
The Port Rules tab (see Figure 14.15) allows you to set the rules by which requests are routed.
The Port Range is the set of port numbers affected by the cluster. You can set these as well as
the protocols handled by the cluster. The Affinity settings determine whether calls are always
routed back to the same server. This is supposed to allow you to maintain state using server-
side techniques such as session variables. However, routing is based on the incoming IP
address, so it’s not reliable. It’s best to set up your cluster and state management system to be
independent of which server in the farm receives the request.
Debugging and Deploying COM+ Applications
369
CHAPTER 14

FIGURE 14.13
Set properties for the cluster.

14

DEPLOYING COM+
DEBUGGING AND
APPLICATIONS
FIGURE 14.14
Set properties for the host.

Along with Network Load Balancing, Microsoft is also introducing a technology known as
Component Load Balancing (CLB). CLB does for components what NLB does for Web
servers. Similar to how you can create a cluster of Web servers, CLB allows you to create a
cluster of COM+ servers. Client requests are then routed to the cluster for processing.
User Services
370
PART IV

FIGURE 14.15
Set properties for the port rules.

Although CLB was originally included as part of COM+, it was removed before shipping
along with the In-Memory Database (IMDB) and the Transactional Shared Property Manager
(TxSPM). Several of these features are now going to ship with the Microsoft Application
Center 2000 due out in Fall 2000.
At this writing, no beta of Application Center 2000 was available. If the schedule holds, how-
ever, it will be available by the time this book is in your hands. I wanted very much to cover
this product in detail, but it will have to wait for the next revision.

EXERCISE 14.1

Distributing a COM+ Application


This exercise uses a simple COM+ component and a fat client in a setup. You will create a
client setup and a proxy installation. After the setup is complete, you’ll establish a group policy
to install the application.
Building the Application
Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
14\Exercise 14-1. This directory contains a COM+ component and a front end.
Debugging and Deploying COM+ Applications
371
CHAPTER 14

Step 2
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
14-1. Copy the contents from the CD-ROM directory into this new directory.

Step 3
Open the project deployment.vbg. In this project, you will find a simple component and an
executable. These are simple projects intended for practicing deployment.

Step 4
Compile the project group.

Step 5
Using the Component Services explorer, create a new COM+ application named Deployment.
Install the compiled ActiveX DLL into the new COM+ application.
Building the Setups
Step 6
In the Component Services explorer, right-click the Deployment application and select
Export. In the Application Export Wizard (see Figure 14.16), create a client proxy named
proxy.msi.

14

DEPLOYING COM+
DEBUGGING AND
APPLICATIONS

FIGURE 14.16
Export the client proxy MSI.

Step 7
Start a new Visual Studio Installer project. When prompted, select to create a Visual Basic
Installer project. This will run a wizard to help create the project. The wizard will present a
dialog asking you to locate the Visual Basic project file to use when building the setup. When
prompted by the wizard, locate the project file for the frontend.vbp project. Figure 14.17
shows the dialog for locating the project.
User Services
372
PART IV

FIGURE 14.17
Select the frontend.vbp file.

Step 8
In the Project Explorer for the new project, locate the dependency file named deploy.dll.
Right-click this file and delete the dependency (see Figure 14.18). This dependency must be
deleted to prevent the Visual Studio Installer from trying to install the component on the client
machine. Rather than install the component, we will deploy a proxy setup from COM+.

FIGURE 14.18
Delete the dependency for the COM+ file.
Debugging and Deploying COM+ Applications
373
CHAPTER 14

Step 9
Under the Target Machine folder, double-click the File System node. This will reveal a work
area with three folders: Application Folder, User’s Desktop, and User’s Start Menu. Add a
shortcut for the application to the User’s Desktop and User’s Start Menu folders by right-
clicking each folder.

Step 10
Change the build configuration from Debug to Release by selecting Build Configuration
from the Build menu. Build the setup by selecting Build from the Build menu.
Creating the Group Policy
Step 11
To have Windows automatically install the client application, you must create a network share
where the MSI files will be located. Create a new folder directly under the root of your home
drive. Share this new directory with everyone and name it Deployment. Then ensure that both
proxy.msi and frontend.msi are located under the network share.

Step 11
Open the Active Directory Users and Computers explorer. Right-click the domain icon and
choose Properties. In the properties dialog box, click the Group Policy tab (see Figure 14.19).

14

DEPLOYING COM+
DEBUGGING AND
APPLICATIONS

FIGURE 14.19
Open the Group Policy tab.

Step 12
On the Group Policy tab, create a new group policy and name it COM+ Distribution. Click
Edit to open the Group Policy snap-in. Then expand the tree to locate the Software
Installation node (see Figure 14.20).
User Services
374
PART IV

FIGURE 14.20
Locate the Software Installation node.

Step 13
Click the Software Installation icon and choose New and then Package from the Action
menu. This will prompt you to locate an MSI file. Choose to “assign” the software, which will
automatically install it when the client is rebooted. Figure 14.21 shows both MSI files assigned
to the new group policy.

FIGURE 14.21
Assign the MSI file to automate installation.
Debugging and Deploying COM+ Applications
375
CHAPTER 14

Step 14
Repeat Step 13 for the frontend.msi file.

NOTE
When installing MSI files, be sure to navigate to them from My Network Places. If you
navigate using the local file system, the MSI files aren’t recognized as available to the
network and installation will fail. Most of my problems implementing group policies
have been because of improperly assigned network shares.

Installing the Software


Step 16
Restart your computer. Your new software should install automatically during the restart
process. Try restarting another computer in the same domain. If you set up a domain policy,
the software will be installed on any machine the next time it’s restarted.

14

DEPLOYING COM+
DEBUGGING AND
APPLICATIONS
COM+ Catalog Administration CHAPTER

15
IN THIS CHAPTER
• The COM+ Administration Object Model 378

• Performing COM+ Administration with the


Windows Scripting Host 383
User Services
378
PART IV

The Component Services explorer, like virtually every other application, is made up of COM
objects. You can program these COM objects to automate administrative tasks or assist in the
setup of a distributed system. Administering COM+ through its objects is known as Catalog
Administration.
Writing applications that use Catalog Administration is a matter of understanding the objects
exposed by the Component Services explorer. Throughout this book, we have worked with the
explorer and the various collections located inside folders. In the Catalog Administration
model, these folders are known as catalogs. Using the COM+ Administration model, you can
access administrative functionality for any computer or component contained inside a catalog.

The COM+ Administration Object Model


Catalog Administration begins by setting a reference to the Component Services
Administration Library. These objects are contained in a library known as the COM+ 1.0
Admin Type Library. Once the reference is set, you can use the library objects to completely
control all facets of administration within COM+. As with all object models, you must have a
strong understanding of the objects within the model before you can begin. Figure 15.1 shows
the Component Services Administration Library Object Model.

COMAdminCatalog

COMAdminCatalogCollection

COMAdminCatalogObject

FIGURE 15.1
Use the Component Services Administration Object Model to automate tasks.

The COMAdminCatalog Object


Catalog Administration begins with the COMAdminCatalog object. A catalog in COM+ is a
source of information originating from any computer on your network where COM+ is run-
ning. By using the Connect method of the COMAdminCatalog object, you can open a connection
with a local or remote server running COM+. This method takes the name of the server as an
COM+ Catalog Administration
379
CHAPTER 15

argument. If you leave the argument as an empty string, a connection with the local server is
opened. When a connection is established, you can use the COMAdminCatalog object to return
COMAdminCatalogCollection objects (discussed in the next section). The following code
shows how to connect to a server running COM+:
Dim objCatalog As COMAdmin. COMAdminCatalog
Dim objRoot As COMAdmin. COMAdminCatalogCollection

Set objCatalog = New COMAdmin. COMAdminCatalog


Set objRoot = objCatalog.Connect(“MachineName”)

After you connect to the desired server, the COMAdminCatalog object allows you to retrieve
additional information from the catalog or perform administrative operations. A large set of
methods gives you the ability to automate many common tasks. Table 15.1 lists the methods
supported by the COMAdminCatalog object.

TABLE 15.1 COMAdminCatalog Methods

Method Description
BackUpREGDB Backs up registration database
Connect Connects to a COM+ catalog
ExportApplication Exports an application or application proxy
GetCollection Returns a collection of catalog information
GetCollectionByQuery Gets a collection of catalog information based on item
keys
GetEventClassesForIID Gets a list of event classes that implement a given inter-
face
GetMultipleComponentsInfo Returns information about all components found in a
given DLL file
ImportComponent Imports a registered component
InstallApplication Installs an application or proxy MSI file
InstallComponent Installs an unregistered component
InstallEventClass Installs a component as an event class
InstallMultipleComponents Installs components from several files
InstallMultipleEventClasses Installs components from several files as event classes 15
QueryApplicationFile Returns information about a COM+ application
COM+ CATALOG
ADMINISTRATION

RefreshComponents Refreshes component information from the Registry


RestoreREGDB Restores registration database
ServiceCheck Checks the status of a COM+ service
ShutdownApplication Shuts down a given application
User Services
380
PART IV

The COMAdminCatalogCollection Object


The COMAdminCatalogCollection object represents a collection of information in COM+. This
information corresponds to the folders in the Component Services explorer. By using
COMAdminCatalogCollection objects, you can return information about such items as comput-
ers, packages, components, roles, interfaces, and methods.
A COMAdminCatalogCollection object can be returned from COMAdminCatalog objects as
when you make an initial connection to a COM+ server, or they can be returned from other
COMAdminCatalogCollection objects. Returning a COMAdminCatalogCollection from either
object is done by using the GetCollection method, which uses a string argument to identify
the collection to return. The string is a predefined value, as shown in Table 15.2.

TABLE 15.2 Component Services Administration Collections


Argument Collection Returned
Applications The collection of all COM+ applications
Components The collection of all components for an application
ComputerList The collection of all machines managed by the explorer
DCOMProtocols The collection of all protocols used by the DCOM system
ErrorInfo A collection of extended error information for operations on
multiple objects
InProcServers The collection of all in-process servers on the system
InterfacesForComponent The collection of all interfaces for a given component
LocalComputer The collection of settings for the local computer
MethodsForInterface The collection of all methods for a given interface
PropertyInfo The collection of properties supported by a given collection
PublisherProperties The collection of properties for a publisher related to a given
subscription
RelatedCollectionInfo A collection of information about other collections that are
associated with the current collection
Roles A collection of roles for a given application
RolesForComponent A collection of roles assigned to a given component
RolesForInterface A collection of roles assigned to a given interface
RolesForMethod A collection of roles assigned to a given method
Root The top-level collection
COM+ Catalog Administration
381
CHAPTER 15

Argument Collection Returned


SubscriberProperties A collection of subscriber properties for a given subscription
TransientSubscriptions A collection of transient subscriptions, which don’t survive a
system failure
UsersInRole A collection of users for a given role

Using the GetCollection method returns a reference to the desired collection; however, the
collection is initially empty. To fill a collection you’ve accessed, you must call the Populate
method of the returned COMAdminCatalogCollection object. In this way, you can move
through the Component Services explorer hierarchy to get to the information you want. The
following code shows how to retrieve all the applications from a server:
Dim objCatalog As COMAdmin.COMAdminCatalog
Dim objRoot As COMAdmin.COMAdminCatalogCollection
Dim objPackages As COMAdmin.COMAdminCatalogCollection

Set objCatalog = New COMAdmin.COMAdminCatalog


Set objRoot = objCatalog.Connect(“”)

Set objPackages = objRoot.GetCollection(“Applications”, “”)


objPackages.Populate

QUICK CHECK 15.1

Catalog Collections
1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 15\Quick Check 15-1. This directory contains a project you can
use to work with COM+ Catalog Collections.
2. Use the Windows Explorer to create a new directory on your hard drive named
COM+\Quick Check 15-1. Copy the contents from the CD-ROM directory into this new
directory.
3. Start Visual Basic. Open the project named collections.vbp. This project contains a
single Standard EXE with a form. Figure 15.2 shows the form. 15
COM+ CATALOG

4. This project is designed to allow you to see some of the collections associated with
ADMINISTRATION

COM+. To view the collections, you must first connect to a COM+ server through the
project by typing the name of a server in the TextBox and clicking the Connect button.
If you want to use your local server, leave the name blank.
User Services
382
PART IV

FIGURE 15.2
This form shows information about related collections in COM+.

5. After the initial list of collections is presented, you can click one and see any other col-
lections below it. The form builds a path for you as you click so you can follow your
progress.

The COMAdminCatalogObject Object


The COMAdminCatalogObject represents an individual member of the
COMAdminCatalogCollection. If, for example, the COMAdminCatalogCollection contains appli-
cations, a COMAdminCatalogObject contains an individual application. Similarly, if you are exam-
ining a COMAdminCatalogCollection of roles, a COMAdminCatalogObject represents a single role.

QUICK CHECK 15.2

COMAdminCatalogObjects
1. Using the files installed from the CD-ROM, locate the directory Project
Templates\Chapter 15\Quick Check 15-2. This directory contains a project you can
use to see several COM+ Catalog Collections and objects.
2. On your hard drive, create a new directory with the Windows Explorer named
COM+\Quick Check 15-2. Copy the contents from the CD-ROM directory into this new
directory.
3. Start Visual Basic. Open the project named quick administration.vbp. This project
contains a single Standard EXE with a form. Figure 15.3 shows the form.
4. Before you can view information, you must connect to a COM+ server by selecting
Local or Remote from the form. If you select Remote, you must provide the name of the
COM+ server. Then, you can click the Connect button to establish a connection. Once
connected, the project builds a list of applications found on the COM+ server.
COM+ Catalog Administration
383
CHAPTER 15

FIGURE 15.3
This form allows you to navigate the COM+ Explorer through code.

5. After the package list is created, you can select any package to view the components and
roles associated with it. Each item is tracked, where appropriate, by its GUID, so we can
get more detailed information for an item.
6. After the components list is populated, you can click any component to view the inter-
faces associated with the component. The interfaces are then listed in a ListBox.
7. When the interface list is populated, you can click any item to view the methods for the
interface.

Performing COM+ Administration with the


Windows Scripting Host
The Windows Scripting Host (WSH) is an updated batch processing engine that administrators
can use to automate tasks. Along with the COM+ Catalog Administration objects, administra-
tors will find WSH to be a valuable tool for maintaining COM+ installations. WSH recognizes
two different languages for batch operations: VBScript and JScript. Both batch files are created 15
using Notepad. Saving a file from Notepad with a .vbs extension tells WSH that VBScript is
COM+ CATALOG
ADMINISTRATION

the batch language for the file, whereas an extension of .js indicates JScript. For Visual Basic
developers using WSH, VBScript is the natural choice. Once the file is created, you can run the
file directly by double-clicking it or can execute it from the command line by typing its file
path and name.
User Services
384
PART IV

When writing batch files, you will face limitations from the VBScript language. For example,
VBScript doesn’t support data types. All variables in VBScript are of type Variant. Variables
are all simply declared with the Dim keyword and a variable name.
WSH goes beyond simply using VBScript for task automation by providing a set of objects
that you can use to assist in administrative tasks. These objects are essentially an object model
for the scripting host. Through the use of these objects, you can perform fundamental adminis-
tration as well as access the COM+ administration objects.

The WScript Object


The WScript object is the center of all operations involving COM components. Using the
CreateObject method of the WScript object, you can create an instance of any COM object
using its ProgID. This includes not only COM+ administration objects, but also other useful
components such as ADO Connections, Commands, and Recordsets. Because all variables in
VBScript are Variants, the following code can be used to create any instance from a ProgID:
Dim MyObject
Set MyObject = WScript.CreateObject(“ProgID”)

Once created, you can call the properties and methods of the object just as you would in Visual
Basic. If the component can return events, WSH will allow you to receive them by providing
an event prefix as the second argument of the CreateObject method. The prefix is used to cre-
ate an event handler for the component, which is created in the format Sub Prefix_EventName.
In addition to the CreateObject method, the WScript object also provides methods such as
Echo for displaying information in a message box and Quit for terminating the Script.
Together, these methods provide essential functionality for the batch program. Table 15.3 lists
the methods and their purposes.

TABLE 15.3 Methods of the WScript Object


Method Description
CreateObject(ProgID,KeyName) Creates an object instance based on a ProgID
DisconnectObject VarName Disconnects an object that was connected for the
purpose of receiving events
Echo Message Outputs information in a message box
GetObject(Path,ProgID,KeyName) Gets an object instance that’s already created
Quit Code Ends the current script

Along with the WScript methods, several properties are also supported. Perhaps the most use-
ful of the available properties is Arguments, which allows you to access command-line argu-
ments that were passed in when the script was started. The Arguments property returns a
COM+ Catalog Administration
385
CHAPTER 15

zero-based array of the arguments passed in to the script. Table 15.4 lists all the properties sup-
ported by the WScript object.

TABLE 15.4 Properties of the WScript Object


Property Description
Application References the WSH application object
Arguments A collection of arguments passed in to the script
FullName The full path to the scripting engine
Name A friendly name for the scripting engine
Path The path to the scripting engine
ScriptFullName Complete path to the running script
ScriptName Name of the running script
Version Current version of WSH

The Shell Object


As we’ve shown, WSH can create an instance of any ActiveX component on your system.
Because WSH is intended for use by administrators, a special ActiveX component ships with
WSH designed to help automate administrative tasks. This component is contained in the file
wshom.ocx, which contains the Shell object. The Shell object contains properties and meth-
ods that allow administrative functions such as creating shortcuts or interacting with the system
registry. Table 15.5 lists the members of the Shell object.

TABLE 15.5 Members of the Shell Object


Member Description
Environment Returns environment information such as processor type and
available memory
SpecialFolders Returns a reference to special folders such as the Desktop or
Start menu
CreateShortcut Creates a shortcut to a file
ExpandEnvironmentStrings Returns environment variables
Popup Pops up a message box
15
COM+ CATALOG
ADMINISTRATION

RegDelete Deletes a Registry key or value


RegRead Reads a Registry value
RegWrite Writes a Registry key or value
Run Starts an executable program
User Services
386
PART IV

QUICK CHECK 15.3

The Windows Scripting Host


1. The Windows Scripting Host is useful for creating scripts that can quickly and easily
automate tasks. In this exercise, you will create a script that can shut down all packages
in a given COM+ installation. This is useful when you want to update components run-
ning under COM+ with a new compiled version. Create a new folder for your scripts in
the File Explorer as COM+\Quick Check 15-3.
2. In this example, we will pass the name of the server as an argument to the script. The
script will connect with the server and then shut down all the COM+ applications it finds
on the server. The code in Listing 15.1 shows the script.

LISTING 15.1 Scripting Application Shutdown


Set Args = WScript.Arguments

‘Connect to server
Set objCatalog = WScript.CreateObject(“COMAdmin.COMAdminCatalog”)
Set objRoot = objCatalog.Connect(Args(0))

If objRoot Is Nothing Then


MsgBox “No Server Available!”
Else

‘Get the Applications Collection


Set objApplications = objRoot.GetCollection(“Applications”, “”)
objApplications.Populate

‘Shutdown each Application


For i=0 To objApplications.Count - 1
WScript.Echo “Shutting Down “ _
& objApplications.Item(i).Name
objCatalog.ShutdownApplication(objApplications.Item(0).Key)
Next

WScript.Echo Args(0) & “ shutdown!”

End If

3. Once the code is entered, save the Notepad file to the directory you created earlier as
shutdown.vbs.
COM+ Catalog Administration
387
CHAPTER 15

4. Now you can run the script from the command line. Select Run from the Windows Start
menu. In the command line, type the complete file path to the VBS file. After the path,
type a space and the name of the server to shut down, similar to the following:
F:\COM+\Quick Check 11-3\shutdown.vbs scotwin2k

Run the script, and all the applications on that server should shut down.

EXERCISE 15.1

Catalog Administration
You can use the Catalog Administration objects to create many different tools for COM+
development. This includes design-time controls for Visual InterDev and code generators for
Visual Basic. In this exercise, you will create a simple wizard that creates a new class module
file based on an interface found in COM+.

Step 1
Using the files installed from the CD-ROM, locate the directory Project Templates\Chapter
15\Exercise 15-1. This directory contains a project you can use to see several COM+
Catalog Collections and objects.

Step 2
On your hard drive, create a new directory with the Windows Explorer named COM+\Exercise
15-1. Copy the contents from the CD-ROM directory into this new directory.

Step 3
Start Visual Basic. Open the project named wizard.vbp. This project contains a single
Standard EXE with a form named frmWizard (see Figure 15.4).

15
COM+ CATALOG
ADMINISTRATION

FIGURE 15.4
The wizard helps create class modules.
User Services
388
PART IV

Step 4
Open the code window for frmWizard. In the [General][Declarations] section, notice sev-
eral sets of variables and enumerations. The variables are used to access the scripting objects;
the enumerations are used to track the steps in the wizard. If you examine the frmWizard form
carefully, notice that it’s built on a tabbed dialog. Each step in the wizard is a tab on the dialog.
Each tab has a set of three buttons for Cancel, Back, and Next operations. These buttons are all
part of control arrays. Therefore, we can use the index of the buttons to determine what step
the wizard is on.

Step 5
The control array for the Next operations is named cmdNext. Each of the four steps has a but-
ton named cmdNext, indexed 0 through 3. When the button is clicked, we can use the index of
the selected button to determine what action to take. These actions include connecting to the
COM+ server, retrieving component information, and generating code.

Step 6
After all the required information is retrieved, the wizard generates a class module that you can
add to a project. The code generation is done by opening a new file and printing out the class
file definition. In the wizard, a custom function named GenerateCode takes care of writing the
code.

Step 7
You should now be able to run the wizard. Fill in the information for each step and generate a
class module. Then open the class module in VB to examine the results. This wizard is fairly
simple, but gives you an idea what’s possible with the Catalog Administration objects.
PART
PubsOnLine.com
V
IN THIS PART
16 Designing the PubsOnLine.com Application 391

17 Building the PubsOnLine.com Application 417


Designing the PubsOnLine.com CHAPTER

16
Application

IN THIS CHAPTER
• Problem Statement 392

• Gathering Requirements 392

• Identifying Actors and Use Cases 393

• Screen Shots and the Paper Prototype 403

• Data Model 407

• System Models 408

• Defining Components 415


PubsOnLine.com
392
PART V

Throughout this book, I have shown techniques for creating COM+ applications on Windows
2000. In this chapter, I bring all the various elements together in a complete application. The
purpose of these final chapters is not only to provide a complete working example, but also to
take you through a significant portion of the software development lifecycle. In my experience,
developers are often concerned with coding techniques at the expense of many of the other key
aspects of creating great software. Therefore, I encourage a close examination of this chapter
before proceeding to the application code that follows.

Problem Statement
The beginning of any software application always begins with a problem statement. The prob-
lem statement is a short (several sentences) description of what the software is intended to do.
This project begins the same way and is described as follows:
The PubsOnLine application will create an e-commerce site that sells books. Customers
of the site will be able to search for books of interest, add them to a shopping cart, and
purchase them. This site is intended to support a 25% increase in book sales.
Although the problem statement is a simple enough effort, we often receive resistance from
developers even at this early stage of the process. Often, developers see no reason to write such
a formal statement of the project because they feel that they already know what has to be done.
Remember that a strong problem statement helps to make the business case for the develop-
ment effort. In the end, the software must support the business objectives of the company; oth-
erwise, the effort is in extreme danger of being cancelled. In this case, there is a statement that
defines what the project will do and why it’s important to the business.

Gathering Requirements
After the project statement is generated, you need to expand the project definition to include
the features that will be in the final project. As discussed in Chapter 3, “Designing COM+
Applications,” gathering requirements is a team effort that should include all the project stake-
holders. A stakeholder is any person in the organization who has an interest in the development
effort or can act as a roadblock to success. Successful project managers are successful expecta-
tion managers; they can’t ignore stakeholders. Instead, they must make everyone feel that their
concerns have been heard. This isn’t to say that every feature demanded by every stakeholder
will appear in the final project; however, they must be gathered and documented. The final fea-
ture set will be based primarily on the business priorities and allotted budget. To this end, the
stakeholders should be guided in an effort to prioritize the feature set. For this project, I identi-
fied the following feature set.
Designing the PubsOnLine.com Application
393
CHAPTER 16

Membership and Personalization 16

PUBSONLINE.COM
This feature is consistently rated among the most important features of the new site. It allows

DESIGNING THE
APPLICATION
customers to be welcomed by name and recognized without requiring a login for each session.
This feature also allows the site to make book recommendations based on user purchases and
activities.

Promotions
This feature represents a wide array of functionality designed to help the site meet its goal of
increased sales. It allows marketing personnel to create discounts, sales, targeted promotions,
cross selling, special offers, and repeat buyer campaigns. This feature also encompasses email
campaigns for customers who want to receive information and offers by email.

Analysis
This feature allows personnel to perform complete analysis of site usage and customer infor-
mation. Personnel could more accurately analyze site traffic and adjust the Web site accord-
ingly. Marketing personnel could also perform “what if” queries through online analytical
processing (OLAP). This provides a tool for answering sales questions and targeting
promotions.

Identifying Actors and Use Cases


After the general requirements are identified, they must be broken into a detailed set of actions
that can be created in the final product. This effort begins by identifying the actors involved.
Remember that actors are generic users or systems that interface with the software system you
are creating. In this project, I have identified two actors: Customer and Administrator. The
Customer actor is any user of the Web site who might purchase a book. The Administrator is
any person who performs administrative tasks on the site such as creating a promotion or per-
forming analysis.
You must also identify the use cases associated with each actor. Remember that a use case is a
text description of steps performed by the system that brings value to the actor. You start by
naming all the different use cases and representing them with a Unified Modeling Language
(UML) diagram. Figure 16.1 shows the use case diagram for our project.
After the actors and use cases are identified, they must be ranked to group them into iterations.
Iterative development is the key to constructing and delivering software in such a way as to
give maximum value. For the first iteration, you must select the key use cases needed to create
the basic functionality of the project. Remember that an iteration differs from a phase in that
iterations must always be complete functional products. They don’t necessarily contain all the
PubsOnLine.com
394
PART V

possible features requested by the stakeholders, but an iteration must be a deployable, usable
application. For this application, I divided the use cases into iterations as follows:

Iteration #1 Iteration #2
Login Analyze Customer Data
Check Out Manage Promotions
View Cart
Add Book to Cart

Login

Analyze Customer Data

Check out

Customer Administrator

Manage Promotions

View Cart

Add Book to Cart

FIGURE 16.1
This diagram shows the actors and associated use cases.

After the iterations are defined, begin to create detailed text-based use case documentation. The
use case documents are intended to provide a narrative of the steps required to complete a use
case. The use case follows a predefined template, which ensures that all the required informa-
tion is captured. Along with the use case text, each use case has at least one associated flow
chart that shows the use case graphically. For this chapter, I present the use cases for the first
iteration, which will be constructed in Chapter 17, “Building the PubsOnLine.com Application.”

Log In
The purpose of this use case is to document the steps necessary to authenticate a site customer.
The use case definition begins with the following general information:
Designing the PubsOnLine.com Application
395
CHAPTER 16

• Primary Actor: Customer 16


• Domain Expert(s): Scot Hillier, Patrick Babcock

PUBSONLINE.COM
DESIGNING THE
APPLICATION
• Revision: 1.00
• Revised Date: 01/15/00
The Use Case Begins When
The customer navigates to the home page of the site.

Pre-Condition(s)
An account has been established for the customer.

Post-Condition(s)
The customer is authenticated. The customer also has a valid shopping cart.

Business Rules
If the customer can’t be authenticated through a cookie, he must fill out a form.
Logging in through the form causes a new shopping cart to be created.

Scenario List
The scenario list names the situations for this use case.
• Perfect: Customer Authenticated
• Alternatives: Form Login Required
• Exceptions: Bad User Name or Password

Narrative: Flow of Events


The flow of events documents the sequence of steps executed for each scenario. Figure 16.2
shows a graphical representation of the steps as a flow chart.

Basic Path: Customer Authenticated


The basic path documents the most common sequence of events for the use case.
1. The use case begins when the customer navigates to the home page of the site.
2. The site looks for a cookie containing the customer’s username.
3. If the cookie doesn’t exist or can’t be authenticated, see “Alternative Path: Form Login
Required.”
If the cookie exists and is authenticated, the customer is welcomed by name.
4. END USE CASE
PubsOnLine.com
396
PART V

Does user have


[ No ] a cookie?
[ Yes ]

Enter Username
and Password

[ No ]
Is cookie valid?

Are Username and


Password Authentic? [ Yes ]
[ No ]
[ Yes ]

New Cart
Created

Username and CartID


Cookies written to client.

Logged In

FIGURE 16.2
This diagram shows the login process as a flow chart.

Alternative Path: Form Login Required


Alternative paths document less likely, but important, scenarios:
1. The customer is welcomed anonymously to the site and invited to log in.
2. The customer fills out a login form.
3. If the username and password can’t be authenticated, see “Exceptions: Bad User Name
or Password.”
If the username and password are authenticated, a new shopping cart is created.
4. The username and cart identifier cookies are written to the client.
5. The customer is welcomed by name.
6. END ALT PATH

Exceptions: Bad User Name or Password


The user is welcomed anonymously and invited to log in.
Designing the PubsOnLine.com Application
397
CHAPTER 16

Add Book to Cart 16

PUBSONLINE.COM
This use case documents the steps necessary to search, display book details, and then add the

DESIGNING THE
APPLICATION
selected book to the shopping cart. The use case definition begins with the following general
information:
• Primary Actor: Customer
• Domain Expert(s): Scot Hillier, Patrick Babcock
• Revision: 1.00
• Revised Date: 01/15/00

The Use Case Begins When


The customer selects to begin a search for books.

Pre-Condition(s)
The user is properly logged in.

Post-Condition(s)
A new book is added to the shopping cart.

Business Rules
When a book is added to the cart, the purchase quantity is automatically set to a single copy.
To buy more than one copy, the quantities must be adjusted separately.
Book searches are based on partial strings entered by the customer.

Scenario List
The scenario list names the situations for this use case:
• Perfect: Book Added
• Alternatives: Quantities Adjusted
• Exceptions: Zero Quantity Entered

Narrative: Flow of Events


The flow of events documents the sequence of steps executed for each scenario. Figure 16.3
shows a graphical representation of the steps as a flow chart.
PubsOnLine.com
398
PART V

Logged In

Request a new Select to add


search book to cart

Cart contents
Search form
displayed
visible
Does customer want to
[ Yes ] change quantities
[ No ]
Request to search by Change quantities
Author, Title, or Publisher for book(s) in cart

New Book in Cart


Search results
displayed

Select a book
of interest

Book details
displayed

FIGURE 16.3
This diagram shows the book addition process as a flow chart.

Basic Path: Book Added


The basic path documents the most common sequence of events for the use case:
1. The use case begins when the customer selects to search for a new book.
2. The customer fills out a form and searches by author, title, or publisher.
3. The customer sees a table of search results.
4. The customer selects a book from the results.
5. Details for the selected book are shown.
6. The customer selects to add the book to her shopping cart.
7. The cart contents are displayed. The new book is shown with a purchase quantity of 1.
8. If the customer wants to buy more than one copy of the book, see “Alternative Path:
Quantities Adjusted.”
9. END USE CASE
Designing the PubsOnLine.com Application
399
CHAPTER 16

Alternative Path: Quantities Adjusted 16


Alternative paths document less likely, but important, scenarios:

PUBSONLINE.COM
DESIGNING THE
APPLICATION
1. The customer enters a new number for the number of copies for any book in the cart.
2. If the customer enters a value of zero for the quantity, see “Exceptions: Zero Quantity
Entered.”
3. The number of copies for purchase is adjusted.
4. END ALT PATH

Exceptions: Zero Quantity Added


Books with a quantity of 0 are removed from the cart.

View Cart
This use case documents the steps necessary to view the cart and adjust purchase quantities.
The use case definition begins with the following general information:
• Primary Actor: Customer
• Domain Expert(s): Scot Hillier, Patrick Babcock
• Revision: 1.00
• Revised Date: 01/15/00

The Use Case Begins When


The customer selects to view the shopping cart.

Pre-Condition(s)
The user is properly logged in.

Post-Condition(s)
Quantities in the cart are adjusted.

Business Rules
Setting a quantity to 0 deletes the book from the cart.

Scenario List
The scenario list names the situations for this use case:
• Perfect: Cart Displayed
• Alternatives: Quantities Adjusted
• Exceptions: Zero Quantity Entered
PubsOnLine.com
400
PART V

Narrative: Flow of Events


The flow of events documents the sequence of steps executed for each scenario. Figure 16.4
shows a graphical representation of the steps as a flow chart.

Logged In

Cart contents
displayed

[ Yes ] Change
quantities?
[ No ]
Change quantities
for book(s) in cart End

FIGURE 16.4
This diagram shows the view cart process as a flow chart.

Basic Path: Cart Displayed


The basic path documents the most common sequence of events for the use case:
1. The use case begins when the customer selects to view the cart.
2. If the customer wants to buy more than one copy of the book, see “Alternative Path:
Quantities Adjusted.”
3. END USE CASE

Alternative Path: Quantities Adjusted


Alternative paths document less likely, but important, scenarios:
1. The customer enters a new number for the number of copies for any book in the cart.
2. If the customer enters a value of zero for the quantity, see “Zero quantity entered.”
3. The number of copies for purchase is adjusted.
4. END ALT PATH

Exceptions: Zero Quantity Added


Books with a quantity of 0 are removed from the cart.
Designing the PubsOnLine.com Application
401
CHAPTER 16

Checkout 16

PUBSONLINE.COM
This use case documents the steps necessary to enter the shipping address, review the book

DESIGNING THE
APPLICATION
list, and provide a credit-card number to complete the purchase. The use case definition begins
with the following general information:
• Primary Actor: Customer
• Domain Expert(s): Scot Hillier, Patrick Babcock
• Revision: 1.00
• Revised Date: 01/15/00

The Use Case Begins When


The customer selects to check out.

Pre-Condition(s)
The user is properly logged in.

Post-Condition(s)
The purchase is complete.

Business Rules
The customer’s password must be verified before the credit card is accepted.

Scenario List
The scenario list names the situations for this use case:
• Perfect: Purchase
• Alternatives: Change Shipping Address
• Exceptions: Bad username or password

Narrative: Flow of Events


The flow of events documents the sequence of steps executed for each scenario. Figure 16.5
shows a graphical representation of the steps as a flow chart.

Basic Path: Purchase


The basic path documents the most common sequence of events for the use case:
1. The use case begins when the customer selects to check out from the site.
2. The shipping address is displayed.
3. If the customer wants to change the shipping address, see “Alternative Path: Change
Shipping Address.”
PubsOnLine.com
402
PART V

Logged In

Shipping address
displayed

Enter new Does customer want to


address change shipping address?
[ Yes ]
[ No ]

Cart contents
displayed

Enter credit card


number and password

[ No ] Is password
correct?
[ Yes ]

Purchase complete

FIGURE 16.5
This diagram shows the checkout process as a flow chart.

4. The cart contents are displayed.


5. The customer enters a credit card number and his password.
6. If the password can’t be authenticated, see “Exceptions: Bad User Name or Password.”
7. The purchase is complete.
8. END USE CASE

Alternative Path: Change Shipping Address


Alternative paths document less likely, but important, scenarios:
1. The customer modifies the shipping address in the form presented.
2. END ALT PATH

Exceptions: Bad User Name or Password


Exceptions capture error conditions in the use case:
1. The customer is given an error message, and the checkout procedure is terminated.
2. The cart and its contents are preserved.
Designing the PubsOnLine.com Application
403
CHAPTER 16

Screen Shots and the Paper Prototype 16

PUBSONLINE.COM
With the use cases completed, there is a complete text-based description of the system to be

DESIGNING THE
APPLICATION
built. The text documentation is further enhanced by the flow charts associated with each use
case. Between the verbal definition of the document and the graphical definition of the flow
chart, I have defined the system functionality with about 80% accuracy. Changes will always
occur in a software development effort; however, you want to minimize the number and impact
of changes.
With the system properly defined, you can begin to create some artifacts that map more closely
to the actual software product. The first artifact you’ll create is the paper prototype, which is
intended to allow the final users to see what the software will look like even before it’s created.
By using these screen shots, you can let the end user operate the software virtually. This way,
you can make changes easily—by simply marking up the paper—without having to break
code. Figures 16.6 through 16.13 show the screen shots for our paper prototype.

FIGURE 16.6
This screen shows the home page.
PubsOnLine.com
404
PART V

FIGURE 16.7
This screen shows the login page.

FIGURE 16.8
This screen shows the search page.
Designing the PubsOnLine.com Application
405
CHAPTER 16

16

PUBSONLINE.COM
DESIGNING THE
APPLICATION
FIGURE 16.9
This screen shows the search results page.

FIGURE 16.10
This screen shows the book details page.
PubsOnLine.com
406
PART V

FIGURE 16.11
This screen shows the cart contents page.

FIGURE 16.12
This screen shows the shipping address page.
Designing the PubsOnLine.com Application
407
CHAPTER 16

16

PUBSONLINE.COM
DESIGNING THE
APPLICATION
FIGURE 16.13
This screen shows the final purchase page.

Data Model
When the paper prototype is complete and approved, you have completed the definition for the
application’s front end. Next, turn your attention to the back end. In this step, you create the
database model for the system. Because modeling the database isn’t a new skill, most of you
are familiar with this process. In fact, my experience is that most development projects begin
with the database model. Although starting at the database doesn’t guarantee failure, I find it
much more useful to understand how users interact with the software before I design the data-
base. Figure 16.14 shows the database model for the first iteration of our application.
PubsOnLine.com
408
PART V

FIGURE 16.14
The database model is created after the paper prototype is complete and approved.

System Models
The most difficult task when designing a system is the transition from screens and use cases to
classes and components. There’s no formula for making this transition. It requires significant
experience with all the technologies involved in the system. At this point, the architect must
mate the front-end screen shots with the back-end database through a series of components.
You accomplish this task by designing the classes necessary to meet the functionality of each
use case. You then prove that functionality by creating a sequence diagram showing the set of
function calls that combine to form each task. This difficult and slow process requires the
architect to think through many of the same problems that developers would otherwise
encounter. This is the true added value of architecture—eliminating problems in the design that
would otherwise result in additional work by the developers themselves.

The Three-Tier Model


The three-tier model is designed to show all the classes in a system divided into their respec-
tive tiers. Normally, we create this diagram after the sequence diagrams are complete. In this
chapter, however, I will present it first. In this way, you can see the final model and better
understand how it was derived. Figure 16.15 shows the three-tier model for the first iteration of
our system.
Designing the PubsOnLine.com Application
409
CHAPTER 16

<<Active Server Page>>


order.asp
<<Class Module>>
CCreateCart
<<Class Module>>
CGetCartDetails
<<Class Module>>
CUpdateCart
16

PUBSONLINE.COM
(from ASP) (from Cart) (from Cart) (from Cart)

DESIGNING THE
APPLICATION
<<Class Module>>
CCart
<<Active Server Page>> (from Cart)
contents.asp <<Class Module>> <<Class Module>> <<Class Module>>
(from ASP) CPutOrder CPutCartItem CDeleteCartItem
(from Cart) (from Cart) (from Cart)

<<Active Server Page>> <<Class Module>>


home.asp CPutADSIAAddress
(from ASP) (from Membership)

<<Class Module>> <<Class Module>>


CMembership CPutADSIAddress
(from Membership) (from Membership)
<<Active Server Page>>
validate.asp
(from ASP)
<<Class Module>>
CGetADSIFriendlyName
(from Membership)
<<Active Server Page>>
shipping.asp
(from ASP)

<<Class Module>>
CGetBookDetails
<<Active Server Page>> (from Books)
<<Class Module>>
results.asp CGetTitlesByPublisher
(from ASP) (from books)
<<Class Module>>
CBooks
<<Class Module>>
(from Books)
<<Active Server Page>> CGetTitlesByAuthor
details.asp <<Class Module>> (from books)
(from ASP) CGetTitlesByTitle
(from Books)

FIGURE 16.15
The three-tier model shows the entire system.

The general architecture of this project uses multiple tiers passing XML streams between
them. Many of the classes we designed accept arguments as XML streams and return results as
XML streams. We want to use XML as the data transport layer because text is the fastest way
to transport the data payload. To reflect this design, we initially created a set of interfaces for
use by the classes in the data services layer. These interfaces are organized into a logical pack-
age, as shown in Figure 16.16.
The IData interface is implemented by any class in the data services layer that returns records.
The ITransact interface is implemented by any class in the data services layer that writes data
back to the database. These are the primary interfaces used in the project. The IWriteErrors
interface is a special COM+ event class that acts as the system-wide error log. Each class in
the system will be able to communicate with the same error-logging class to record all system
PubsOnLine.com
410
PART V

errors in a standard location. Recall that COM+ event subscribers require an interface to act as
the event class.

<<Class Module>>
IData

GetData(strParameters : String) : String

<<Class Module>>
ITransact

PutData(strParameters : String) : Long

<<Class Module>>
IWriteErrors

Send(IngNumber : Long, strDescription : String, strComponent : String, strProcedure : String)

FIGURE 16.16
The Interfaces package defines the interfaces used by classes in the system.

Along with the interfaces, our architecture also depends on a payload managing component.
This component is responsible for transforming data when it enters or exits a component in the
system. I have discussed payload management earlier in the book, and this system simply takes
advantage of that work to easily transform data between recordsets, XML, Field objects, and
HTML. The payload manager consists of two classes: Dataset and Field. The Dataset class
contains all the properties and methods necessary to convert datasets between various formats,
whereas the Field object acts as a specialized collection that you can use to pass parameters
into components. With the exception of the IWriteErrors interface, neither the interfaces nor
the payload manager are intended to be deployed in a COM+ application. Instead, they are
called by COM+ components when needed.
After the foundational interfaces and payload manager classes are designed, you are ready to
design the COM+ components themselves. Again, return to the use cases to break down the
design work into manageable parts. For this system, you know that some functions, such as
logging in, will require access to the Active Directory, whereas other functions will access
SQL Server. You can use this knowledge to help decide where functions will live within the
system components.

Log In
The Log In use case requires authentication of the user against the Active Directory. For all
Active Directory functions, you define a single business object to handle them called
CMembership. This component will enlist data services components as necessary to read and
Designing the PubsOnLine.com Application
411
CHAPTER 16

write data to Active Directory. For the Log In use case, you might be authenticating using 16
either an HTML form or a cookie. Therefore, you need two separate methods on the

PUBSONLINE.COM
DESIGNING THE
CMembership class to support the functionality. The initial call will always come from a Web

APPLICATION
page to CMembership where it will be processed and resulting HTML returned. Figure 16.17
shows the sequence diagram for an HTML form login.

: validate.asp : : CCreateCart
: Customer CMembership CGetADSIFriendlyName

Object : validate.asp
Login( )

FIGURE 16.17
This is the sequence diagram for an HTML form login.

The Customer actor begins the sequence by filling out a form and submitting it to
validate.asp. Along with the business and data classes, each significant ASP page is also
shown in the model. The validate.asp page calls the Login method of the CMembership class.
In the CMembership class, the username and password are extracted from the HTML form. This
data is then passed to the CGetADSIFriendlyName class in the data services layer. This class
attempts to create the friendly name of the user based on the credentials entered. If the attempt
is successful, the CMembership class uses an XSL style sheet to format a return page that wel-
comes the user by name. Successful logins result in the creation of a new empty shopping cart.
The user also receives two cookies: CARTID and USERNAME. If the attempt to return a
friendly name is unsuccessful, the login is assumed to have failed.
If the Customer actor has logged in before, the system can attempt to perform a validation
based on the USERNAME cookie. This requires a call to the AuthenticateCookie method of
the CMembership object. Figure 16.18 shows the sequence for a cookie authentication.
PubsOnLine.com
412
PART V

: home.asp : :
: Customer CMembership CGetADSIFriendlyName

Login( )

FIGURE 16.18
This is the sequence diagram for a cookie-based login.

Add Book to Cart


Adding a book to the shopping cart is a multi-step process that requires several actions on the
part of the user. Each action must be modeled for the application to work. Selecting a book
begins by searching. In this case, the Customer actor fills out a search form and submits it. The
results are then shown in a table. A book-related database operations are managed by the
CBooks class. In the case of searching, the results.asp page calls the Search method of
CBooks. A query is made against the database by author, title, or publisher, and the results are
returned as XML. The XML is formatted into HTML by an XSL style sheet. Figure 16.19
shows the sequence of calls involved in searching the database.

When the search results are viewed, the Customer actor can select a single book and view
details about the book. From the details.asp page, the book can be added to the shopping
cart. Showing the book details requires a call to the ShowDetails method. If the Customer
actor wants to add the book to the shopping cart, a call to CPutCartItem is performed. Figure
16.20 shows the sequence diagram for adding a book to the shopping cart.
Designing the PubsOnLine.com Application
413
CHAPTER 16

16

PUBSONLINE.COM
DESIGNING THE
: results.asp CBooks : : :

APPLICATION
: Customer CGetTitlesByAuthor CGetTitlesByPublisher CGetTitlesByTitle

Search( )

Object : Customer

FIGURE 16.19
This is the sequence diagram for searching the database.

: details.asp CBooks : :
: Customer CGetBookDetails CPutCartItem

ShowDetails ( )

FIGURE 16.20
This is the sequence diagram for adding a book to the shopping cart.
PubsOnLine.com
414
PART V

After a new book is added to the shopping cart, the cart contents are displayed. New books are
automatically set to purchase a single copy. However, the Customer actor might want to adjust
the quantities purchased. This requires a call to the ShowCart method of the CCart class. CCart
is the business services class responsible for managing the shopping cart. The ShowCart
method can retrieve the contents of a cart and adjust the quantities of each book. If the
Customer actor adjusts the quantity of any book to zero, the ShowCart method calls the
CDeleteCartItem class and the book is removed from the cart. This same sequence of events
occurs anytime the user simply asks to view the cart. Therefore, it applies to the View Cart use
case as well. Figure 16.21 shows the sequence diagram for adjusting book quantities.

: contents.asp CCart CUpdateCart :


: Customer CDeleteCartItem

ShowCart ( )

FIGURE 16.21
This is the sequence diagram for adjusting book quantities.

Check Out
Checking out and completing an order requires two separate processes:
1. The shipping address must be verified, and then the credit card must be authenticated. In
this system, the shipping information is kept in the Active Directory. Therefore, the ship-
ping information is managed by the CMembership class. During the checkout process,
the shipping address is retrieved and presented to the user. Changes to the address are
Designing the PubsOnLine.com Application
415
CHAPTER 16

submitted and processed from the same page. Figure 16.22 shows the sequence diagram 16
for changing the shipping address.

PUBSONLINE.COM
DESIGNING THE
APPLICATION
: shipping.asp : : :
: Customer CMembership CGetADSIAddress CPutADSIAddress

ShowAddress ( )

ShowAddress ( )

FIGURE 16.22
This is the sequence diagram for changing the shipping address.

2. The cart contents are displayed and the credit card information is requested. In this oper-
ation, the user must also provide her site password along with the credit card for
enhanced security. The password is then authenticated before the order is completed.
Figure 16.23 shows the sequence diagram for completing the order.

Defining Components
Component definition requires the architect to decide how to place the various class modules
inside ActiveX DLLs. This structure defines for the developers how to build the components
and divide the work. Because COM+ applications are independent of the component packag-
ing, you can define your packages in any number of ways. We’ve defined our components by
tiers. After this definition is complete, the design can be delivered to the project manager for
construction. Figure 16.24 shows the component model for the system.
PubsOnLine.com
416
PART V

: order.asp : CCart : CPutOrder


: Customer

Order ( )

FIGURE 16.23
This is the sequence diagram for completing the order.

<<ActiveX DLL>> <<ActiveX DLL>>


NTSPayload POLBixServ

<<ActiveX DLL>>
POLCommon

<<ActiveX DLL>> <<ActiveX DLL>>


POLinterfaces POLDataServ

FIGURE 16.24
This is the component diagram for the system.
Building the PubsOnLine.com CHAPTER

17
Application

IN THIS CHAPTER
• Development Environment 418

• Creating the Database 419

• Creating the COM+ Components 425

• Creating the Web Interface 445


PubsOnLine.com
418
PART V

Chapter 16 examined the design documents for the PubsOnLine e-commerce site. In this chap-
ter, we will create the site based on Chapter 16’s design. Creating the site will require us to
prepare an appropriate development environment, build a SQL Server database, create COM+
components, and finally build the Web interface.

Development Environment
Although this project is designed to run as a distributed application across multiple servers,
most readers won’t have access to a multi-server environment. Therefore, I elected to present
this exercise for development on a single machine. This will simplify the effort and allow me
to focus on the logical architecture.
Before you begin this exercise, you should have available a Windows 2000 Server with Active
Directory installed. Installing Active Directory is known as promoting the server. Active
Directory is installed by using the Configure Your Server applet (see Figure 17.1).

FIGURE 17.1
Install Active Directory before beginning the exercise.

In addition to Active Directory, you should establish yourself as administrator for the server.
Administrator privileges are necessary for establishing users, groups, and permissions neces-
sary to complete the exercise. For example, you will be creating a user under which the COM+
applications will run.
Other than these special considerations, you should have Visual Basic, Visual InterDev, and
SQL Server installed. You should have full administrator privileges on your SQL Server instal-
lation and be completely familiar with the use of all development tools. When this environment
is established, we are ready to start.
Building the PubsOnLine.com Application
419
CHAPTER 17

Creating the Database


The project begins with the creation of the SQL Server database. The database will be created
by using a script found on this book’s CD-ROM. The product data will then be imported from
a Microsoft Access database also located on the CD-ROM. Figure 17.2 shows the data model
for the SQL Server database we will create.

17

PUBSONLINE.COM
BUILDING THE
APPLICATION
FIGURE 17.2
Begin the project by creating the SQL Server database.

The database structure allows for storage of the book information and the shopping cart. The
tables that track the books are relatively straightforward and should be familiar to many devel-
opers. These tables simply associate the title, author, and publisher information. A many-to-
many relationship exists between authors and titles because one author might appear in several
books or a single book might have several authors.
The shopping cart tables are also fairly simple. Each shopping cart is identified by a primary
key. Adding books to the shopping cart makes entries in the CartDetails table. Keeping the
shopping cart in the database is simple enough, but it has the drawback of requiring a trip to
the database for every Web page in the application. This is because the application state isn’t
maintained across calls to the site. On every call, the cart must be retrieved from the database.
Now that you understand the database structure, you can create the database in SQL Server.
You will need this book’s CD-ROM, which contains the database script and the data to import.
The following exercise walks you through the database creation.
PubsOnLine.com
420
PART V

EXERCISE 17.1

Creating the Database in SQL Server


Step 1
Start the SQL Server Enterprise Manager. Once the Enterprise Manager is running, expand the
tree view and locate the Databases folder. Figure 17.3 shows the Enterprise Manager running
and the Databases folder selected.

FIGURE 17.3
Locate the Databases folder in the SQL Server Enterprise Manager.

Step 2
With the Databases folder selected, create a new database by choosing New Database from the
Action menu. In the Database Properties dialog, name the new database PubsOnLine. If you
are an advanced user, you might want to change some of the database properties at this point,
but the default values should be acceptable for the project. Figure 17.4 shows the Database
Properties dialog.

Step 3
Now that you’ve created the database, you are ready to run the SQL script to create the actual
database structure. To run the SQL script, you need to start the SQL Server Query Analyzer by
selecting SQL Server Query Analyzer from the Tools menu.
When the Query Analyzer starts, you will see a command-line window in which you can enter
SQL statements to run against a database. The Query Analyzer contains a drop-down list of all
databases in your SQL Server installation. Drop down this list and select the PubsOnLine data-
base. Figure 17.5 shows the Query Analyzer with the PubsOnLine database selected.
Building the PubsOnLine.com Application
421
CHAPTER 17

17

PUBSONLINE.COM
BUILDING THE
APPLICATION
FIGURE 17.4
Create a new blank database.

FIGURE 17.5
The SQL Server Query Analyzer is used to execute SQL statements against databases.

Step 4
In the SQL Server Query Analyzer, open the SQL Script for creating the databases by selecting
Open from the File menu. In the Open File dialog, locate the SQL script on the CD-ROM in
the directory Project Templates\Chapter 17\Database\SQL Script\PubsOnLine.sql.
Open this file in the Query Analyzer.
The SQL script is a series of statements that will build the tables and stored procedures to cre-
ate a blank database. Run this script on the PubsOnLine database by selecting Execute from
the Query menu. When the script is complete, you will see the message The command(s)
completed successfully. Close the Query Analyzer when you are finished.
PubsOnLine.com
422
PART V

Step 5
When you’ve finished building the database, you should be able to return to the SQL
Enterprise Manager and view the tables and stored procedures. Examine these items by click-
ing the Tables and Stored Procedures folders beneath the PubsOnLine database.

Step 6
This project expects to use SQL Server standard security. This means that access to SQL
Server databases is determined by a separate username and password. Ensure that your SQL
Server installation is set up to use standard security by right-clicking your server in the SQL
Enterprise Manager and selecting Properties. In the SQL Server Properties dialog, click the
Security tab. Verify that authentication is set to SQL Server and Windows NT. Figure 17.6
shows the Properties dialog with the correct settings for standard security.

FIGURE 17.6
Ensure that your SQL Server uses standard security.

Step 7
In this application, we will use standard database security in a COM+ constructor string. This
username and password are used for every transaction performed by a COM+ component.
Therefore, we will need to establish a special account for accessing data in SQL Server.
In the SQL Enterprise Manager, click the Logins icon in the Security folder to see the avail-
able defined logins. In this folder, we need to create a new login for the COM+ data services
components. Do so by selecting New Login from the Action menu.
Building the PubsOnLine.com Application
423
CHAPTER 17

In the SQL Server Login Properties dialog, add a new login named COMDATA (see Figure
17.7). Select to authenticate the login by using SQL Server Authentication. Enter a new pass-
word for this account as compassword. Set the default database to PubsOnLine.

17

PUBSONLINE.COM
BUILDING THE
APPLICATION
FIGURE 17.7
Set up a new login for COM+ components.

With the SQL Server Login Properties dialog still open, click the Database Access tab to
assign permissions to the new login. On this tab, permit access to the PubsOnLine database for
the new login. For each database you permit, assign the new login the roles of public and
db_owner. Figure 17.8 shows the dialog with the correct settings.

FIGURE 17.8
Assign permissions and roles for the new login.
PubsOnLine.com
424
PART V

Step 8
Now that the database structure is created, you are ready to load the database with data.
Loading the database is accomplished by importing data from a Microsoft Access database on
the CD-ROM. Begin the import process by right-clicking the PubsOnLine database in the
Enterprise Manager and selecting All Tasks and then Import Data. This action will start the
Data Transformation Services Import Wizard (see Figure 17.9).

FIGURE 17.9
Start the import process from the Enterprise Manager.

In the first step of the wizard, you will be asked to select a data source. Select to import data
from a Microsoft Access database and locate the database on the CD-ROM under Project
Templates\Chapter 17\Database\Import Data\PubsOnLine.mdb. Figure 17.10 shows the
wizard with the correct information.

FIGURE 17.10
Import from the Microsoft Access database.
Building the PubsOnLine.com Application
425
CHAPTER 17

In the next step of the wizard, select to import the data into the PubsOnLine database. Make
sure that you have appropriate permissions to accomplish the task. Keep working through the
wizard until you are prompted to identify which tables to import. In this step, select all the
tables (see Figure 17.11).

17

PUBSONLINE.COM
BUILDING THE
APPLICATION
FIGURE 17.11
Import all the tables.

Have the wizard run the import immediately and click the Finish button. The data will then be
imported. After this operation, your database is ready for use.

NOTE
Depending on the order that the tables are imported, you might receive an error on
the TitleAuthor and CartDetails tables. These errors are usually key violations. If
this error occurs, simply rerun the wizard and import only the tables that originally
had errors.

Creating the COM+ Components


Now that the database is complete, we can create the COM+ components in Visual Basic. This
application uses a set of templates that form a framework for creating COM+ applications. The
templates are intended to appear in the Visual Basic project dialog. Therefore, the first thing
you must do is retrieve the templates from the CD-ROM. When the templates are available, we
will use them to create data and business services.
PubsOnLine.com
426
PART V

EXERCISE 17.2

Creating the COM+ Components in VB


Step 1
Locate the templates for this project on the CD-ROM in the path Tools\VB Templates. In this
directory, you will find subfolders that map to the template directories available in your Visual
Basic installation. You will copy all the folders beneath the VB Templates folder to your Visual
Basic installation.
The destination for the templates can be found under Program Files\Microsoft Visual
Studio\VB98\Template (see Figure 17.12). Copy the templates from the CD-ROM into this
directory.

FIGURE 17.12
The CD-ROM templates must be copied to your VB installation.

Step 2
After the templates are copied, you can use them to start any COM+ application. To use the
templates, start Visual Basic. The framework project appears in the New Project dialog as
COM+ Application. Select to start a new project based on this template. Figure 17.13 shows
the template in the dialog.
Building the PubsOnLine.com Application
427
CHAPTER 17

17

PUBSONLINE.COM
BUILDING THE
APPLICATION
FIGURE 17.13
Select the template to start a new COM+ application.

The new project you create will already have several key aspects of the final application.
Notice that projects have been created for each layer in the application as well as interfaces,
common functions, and the payload.
Begin by examining the DNAPayload project. This project is complete when you create the new
project. Its purpose is to manage the transfer of data between layers and the transformation of
data within layers of the application. Understanding the DNAPayload project is the key to
understanding all the components in the application.
The DNAPayload project consists of two classes: Dataset and Field. The Dataset class is used
for transforming data between various forms, including ADO Recordsets, XML, and HTML.
Within the framework, data is always transferred between layers using XML. Data is always
operated on within a layer as an ADO Recordset. This allows transfers to occur in a string, the
most efficient format, and operations to occur in an object-oriented format, the Recordset. I
find these transformations to be ideal in creating an efficient, maintainable application. When
the data is finally sent to the browser, we can use the Dataset object to transform the data into
HTML, which can be viewed by any browser.
The Field class plays a special role in the DNAPayload project. The Field object is a member
of the Fields collection, which is managed by the Dataset class. The collection of Fields is
used to accept input parameters from the user. These parameters can include things such as
username, password, and search criteria. Chapter 6, “COM+ Data Components,” contains a
complete description of DNAPayload.
PubsOnLine.com
428
PART V

Now examine the Common project, in which you will find a single class named CLogger. This
class is intended to be deployed as a COM+ event subscriber. The purpose of the class is to
establish a common error log that can be used by every component in the system. We find this
type of common logging to be invaluable when debugging the system. Chapter 9, “COM+
Business Features,” discusses COM+ events in detail.
The only other project that contains classes is Interfaces. This project contains three inter-
faces: IReadData, IWriteData, and IWriteErrors. IReadData and IWriteData are imple-
mented by data service classes that read from a data source or write to a data source,
respectively. The IWriteErrors interface is the actual COM+ event class. This interface is
called whenever a component needs to report an error. It’s the interface implemented by the
CLogger class.

The framework also provides data and business services projects, but these projects don’t have
any classes in them yet. As we move ahead in this chapter, we will add classes to these projects
and deploy the classes in a COM+ application. We’ll begin with the data services layer.

Data Services
The data services layer consists of classes that wrap stored procedures in the database or access
the Active Directory. Because these classes are all constructed similarly, we’ll use a template to
help speed development. In this section, you will create one class for reading and one for writ-
ing using the templates you installed earlier.

EXERCISE 17.3

Creating the Data Services Framework Layer


Step 1
In Visual Basic, select the DataServ project to make it active. Add a new data access class to
this project by selecting Add Class Module from the Project menu. This opens the Add Class
Module dialog. In this dialog, you will see several of the templates you added earlier. You are
going to create a data class that reads book data from the database, so select to add a class
based on the CReadData template. Figure 17.14 shows the template in the dialog.

Step 2
Immediately change the name of the class to CGetCartDetails. This class is used to retrieve
the contents of the shopping cart for display. On opening the class, notice that it already has a
significant amount of code in it. The template contains almost everything you need for a data
class. The appropriate interface is already implemented, the DNAPayload is used to handle data,
and the common system log is referenced for errors. Listing 17.1 shows the template code.
Building the PubsOnLine.com Application
429
CHAPTER 17

17

PUBSONLINE.COM
BUILDING THE
APPLICATION
FIGURE 17.14
Select the CReadData template.

LISTING 17.1 CReadData Template Code

Option Explicit
Option Compare Text

‘NOTES:
‘1) This component requires construction to be enabled
‘2) This project must have a references to:
‘a. COM+ Services Library
‘b. IReadData Interface
‘c. The DNAPayload object
‘d. ADO 2.5 Library
‘e. IWriteErrors Interface

‘Interfaces
Implements IReadData
Implements COMSVCSLib.IObjectConstruct

‘Construction string
Private m_Connect As String

Private Function IReadData_GetData _


(ByVal strParameters As String) As String

‘Author:
‘Purpose:
‘Rules:
‘Revisions:

On Error GoTo GetDataErr


PubsOnLine.com
430
PART V

LISTING 17.1 Continued


Dim objLog As POLInterfaces.IWriteErrors
Dim lngNumber As Long
Dim strDescription As String
Dim objInbound As DNAPayload.Dataset
Dim objOutbound As DNAPayload.Dataset
Dim objRecordset As ADODB.Recordset

‘Get the Object Context


Dim objContext As COMSVCSLib.ObjectContext
Set objContext = GetObjectContext

‘Create Payload Objects


Set objInbound = New DNAPayload.Dataset
Set objOutbound = New DNAPayload.Dataset
objInbound.Stream = strParameters

‘Execute Query
Set objRecordset = New ADODB.Recordset
‘**TO DO: Add SQL Statement ***
objRecordset.Open _
“EXEC StoredProcName Arg1, Arg2, Arg3”, _
m_Connect, adOpenStatic
Set objOutbound.ADORecordset = objRecordset

‘Tell COM+ we’re done


objContext.SetComplete

GetDataExit:
‘Stream Payload back
IReadData_GetData = objOutbound.Stream
Exit Function

GetDataErr:

‘Tell COM+ we failed


objContext.SetAbort

‘Set Error Codes


lngNumber = Err.Number
strDescription = Err.Description
objOutbound.ErrNumber = lngNumber
objOutbound.ErrDescription = strDescription

‘Log Error
Set objLog = New POLInterfaces.IWriteErrors
Building the PubsOnLine.com Application
431
CHAPTER 17

objLog.Send lngNumber, strDescription, _


“Class name here!”, “GetData”
Resume GetDataExit

End Function

Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object)

‘Author: Scot P. Hillier


‘Purpose: Retrieve the UDL connect string
‘Rules: Construction must be enabled for this component
‘Revisions: 2/4/00 Original
17

PUBSONLINE.COM
BUILDING THE
APPLICATION
m_Connect = pCtorObj.ConstructString

End Sub

Step 3
To complete the data class, you have only to add the correct SQL statement to the template. In
this case, you must reference the stored procedure to return the shopping cart. Locate the com-
ment in the template that states TO DO: Add SQL Statement. Under this comment, you will
see the following code:
objRecordset.Open _
“EXEC StoredProcName Arg1, Arg2, Arg3”, _
m_Connect, adOpenStatic

Edit this line of code to execute the appropriate stored procedure. The stored procedure takes
as an input the CartID of the shopping cart to return. The final code should appear as follows:
objRecordset.Open _
“EXEC polGetCartDetails ‘“ & _
objInbound(“CartID”).FieldValue & “‘“, _
m_Connect, adOpenStatic

The trouble with using any framework, of course, is that you must understand the framework
before you can realize the value. This project is no different; you should pause now to truly
understand the code contained in the template.
As stated earlier, the key to understanding the application is the DNAPayload project. This pro-
ject brings search parameters into the data class and search results out of the data class. Data
entering or leaving the class is in XML format. Data within the class is operated on as a Field
collection for search parameters and a Recordset for results. Figure 17.15 shows the data trans-
formation process.
PubsOnLine.com
432
PART V

Start

Search parameters
enter the data class
as an XML string

The data class


creates a
DNAPayload object
and loads the XML

The data class


retrieves the search
parameters from
the Fields collection

The data class runs


a query on the
database that
returns a Recordset

The data class


creates a new
DNAPayload object
and loads the
Recordset

The data class


returns the results
of the query as an
XML string

End

FIGURE 17.15
Data is transformed by the DNAPayload.
Building the PubsOnLine.com Application
433
CHAPTER 17

The process shown in the flow chart is the same for every data class. This greatly simplifies
development and allows the use of interfaces and templates to construct the application. The
template also contains error handling code to log any errors as well as append special error
nodes to the outgoing XML. These processes are the heart of the data services framework.
Now that you’ve created a data class that reads from the database, we’ll create one that writes
to the database. Many aspects of the code are similar between reading and writing. You’ll
notice again the essential role played by the DNAPayload. However, classes that write to the
database will support transactions and have a slightly different interface.
17

PUBSONLINE.COM
EXERCISE 17.3 CONTINUED

BUILDING THE
APPLICATION
Continuing the Preceding Steps
Step 4
With the DataServ project still active, select Add Class Module from the Project menu. In the
Add Class Module dialog, add a new class based on the CWriteData template. Immediately
change the name of the class to CPutCartItem. This data class is responsible for adding new
books to the shopping cart. Listing 17.2 shows the code from the template.

LISTING 17.2 CWriteData Template Code

Option Explicit
Option Compare Text

‘NOTES:
‘1) This component requires construction to be enabled
‘2) This project requires references to:
‘a. IWriteData Interface
‘b. COM+ Services Library
‘c. ADO 2.5
‘d. IWriteErrors Interface
‘e. The DNAPayload object

‘Interfaces
Implements POLInterfaces.IWriteData
Implements COMSVCSLib.IObjectConstruct

‘Construction string
Private m_Connect As String

Private Function IWriteData_PutData(ByVal strParameters As String) As Long


PubsOnLine.com
434
PART V

LISTING 17.2 Continued


‘Author:
‘Purpose:
‘Rules:
‘Revisions:

On Error GoTo PutDataErr

Dim objLog As POLInterfaces.IWriteErrors


Dim lngNumber As Long
Dim strDescription As String
Dim objInbound As DNAPayload.Dataset
Dim objConnection As ADODB.Connection

‘Get the Object Context


Dim objContext As COMSVCSLib.ObjectContext
Set objContext = GetObjectContext

‘Create Payload Object


Set objInbound = New DNAPayload.Dataset
objInbound.Stream = strParameters

‘Execute Query
Set objConnection = New ADODB.Connection
objConnection.ConnectionString = m_Connect
objConnection.Open
‘***TO DO: Add SQL Statement***
objConnection.Execute _
“EXEC StoredProcName Arg1, Arg2, Arg3”

‘Tell COM+ we’re done


objContext.SetComplete

PutDataExit:
IWriteData_PutData = lngNumber
Exit Function

PutDataErr:

‘Tell COM+ we failed


objContext.SetAbort

‘Set Error Codes


lngNumber = Err.Number
strDescription = Err.Description
Building the PubsOnLine.com Application
435
CHAPTER 17

‘Log Error
Set objLog = New POLInterfaces.IWriteErrors
objLog.Send lngNumber, strDescription, _
“Class name here!”, “PutData”
Resume PutDataExit

End Function

Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object)

‘Author: Scot P. Hillier


‘Purpose: Retrieve the UDL connect string
17

PUBSONLINE.COM
‘Rules: Construction must be enabled for this component

BUILDING THE
APPLICATION
‘Revisions: 2/4/00 Original

m_Connect = pCtorObj.ConstructString

End Sub

Step 5
Again, most of the code is written for you. All you have to do is fill in the appropriate SQL
statement. In this case, the statement is a stored procedure that writes to the database. Locate
the following code in the new class module:
‘***TO DO: Add SQL Statement***
objConnection.Execute _
“EXEC StoredProcName Arg1, Arg2, Arg3”

This code uses the Execute method of an ADO Connection to write to the database. Modify
this code to call the correct procedure and pass arguments from the DNAPayload. The final
code should appear as follows:
objConnection.Execute _
“EXEC polPutCartItem “ & _
objInbound(“CartID”).FieldValue & “,’” _
& objInbound(“ISBN”).FieldValue & “‘,” _
& objInbound(“Price”).FieldValue

Step 6
Now that you’ve created two data classes, we will add the rest of the classes directly from the
CD-ROM, located in the Project Templates\Chapter 17\Components\Data Services
folder. Begin by saving the Visual Basic project you’ve been working on. Next, copy the
remaining classes from the CD-ROM into your project directory. Finally, carefully add each of
the data classes to the DataServ project to complete the data services layer.
PubsOnLine.com
436
PART V

NOTE
Be careful when saving the project. You might want to create separate directories for
each project in the group. Organizing the projects carefully will allow you to add
classes more easily from the CD-ROM.

Business Services
Unlike the data services layer, the business services layer doesn’t lend itself quite as well to the
use of templates. Although some aspects of the business classes are repeatable, such as error
handling, much of each class is unique because of the differing business rules contained by
each class. For that reason, we will add the business services classes directly from the CD-
ROM and then examine their structure.

EXERCISE 17.4

Creating the Framework’s Business Services Layer


Step 1
Locate the business services classes on the CD-ROM. You will find the additional classes
located on the CD-ROM in the Project Templates\Chapter 17\Components\Biz Services
folder. Copy these classes from the CD-ROM into your project directory and then carefully add
them to the BizServ project.

Step 2
Open the CCart class in Visual Basic and examine the ShowCart method. This method is called
by an Active Server Page to display the cart contents. This method in turn calls the
CGetCartDetails data class you created earlier. Listing 17.3 shows the code for the ShowCart
method.

LISTING 17.3 ShowCart Method

Public Sub ShowCart()

‘Author: Scot P. Hillier


‘Purpose: Show the cart contents
‘Rules: Can add or delete depending upon what link called it
‘Revisions: 2/7/00 Original

On Error GoTo ShowCartErr


Building the PubsOnLine.com Application
437
CHAPTER 17

Dim objLog As POLInterfaces.IWriteErrors


Dim lngNumber As Long
Dim strDescription As String
Dim objParams As DNAPayload.Dataset
Dim objReturn As DNAPayload.Dataset
Dim objDataObject As POLInterfaces.ITransact
Dim objCartObject As POLInterfaces.IData
Dim vData As Variant

‘Get the Object Context


Dim objContext As COMSVCSLib.ObjectContext
Set objContext = GetObjectContext 17

PUBSONLINE.COM
BUILDING THE
‘Create Payload Object

APPLICATION
Set objReturn = New DNAPayload.Dataset

‘Add to cart
If objContext(“Request”).QueryString(“add”) = “yes” Then

‘Create Parameter Payload


Set objParams = New DNAPayload.Dataset
objParams.Add “CartID”, adVarChar, _
objContext(“Request”).Cookies(“CARTNUM”), 50
objParams.Add “ISBN”, adVarChar, _
objContext(“Request”).Form(“txtISBN”), 50
objParams.Add “Price”, adCurrency, _
objContext(“Request”).Form(“txtPrice”)

‘Call Data Services


Set objDataObject = New POLDataServ.CPutCartItem
objDataObject.PutData objParams.Stream

End If

‘Update Quantities
If objContext(“Request”).QueryString(“Update”) = “yes” Then

‘Create Parameter Payload


Set objParams = New DNAPayload.Dataset
objParams.Add “CartID”, adVarChar, _
objContext(“Request”).Cookies(“CARTNUM”), 50

For Each vData In objContext(“Request”).Form


objParams.Add vData, adVarChar, _
objContext(“Request”).Form(vData), 50
Next

‘Call Data Services


Set objDataObject = New POLDataServ.CUpdateCart
objDataObject.PutData objParams.Stream
PubsOnLine.com
438
PART V

LISTING 17.3 Continued


End If

‘Get Cart Contents


Set objParams = New DNAPayload.Dataset
objParams.Add “CartID”, adVarChar, _
objContext(“Request”).Cookies(“CARTNUM”), 50
Set objCartObject = New POLDataServ.CGetCartDetails
objReturn.Stream = objCartObject.GetData(objParams.Stream)

‘Create Response Page


objReturn.LoadXSL m_WebSite & “\xsl\cart.xsl”
objReturn.XML2HTML
objContext(“Response”).Write objReturn.HTML

‘Tell COM+ we’re done


objContext.SetComplete

ShowCartExit:
Exit Sub

ShowCartErr:

‘Tell COM+ we failed


objContext.SetAbort

‘Set Error Codes


lngNumber = Err.Number
strDescription = Err.Description

‘Log Error
Set objLog = New POLInterfaces.IWriteErrors
objLog.send lngNumber, strDescription, _
“POLBizServ.CCart”, “ShowCart”
Resume ShowCartExit

End Sub

The ShowCart method uses the Active Server Page context to interact with the Request,
QueryString, and Response objects. This enables the business class to receive data from forms
on Web pages and return data as formatted HTML. Handling the input parameters from the
forms and outputting the HTML is the job of the DNAPayload, which again has a major role.
Figure 17.16 shows the process executed by the ShowCart method to display the shopping cart
in a Web page.
Building the PubsOnLine.com Application
439
CHAPTER 17

Start

ASP Page calls


ShowCart method

Update Cart
Add to Cart? No
Quantities

Yes
17

PUBSONLINE.COM
BUILDING THE
APPLICATION
Get item
information from
ASP Request
object

Create
DNAPayload and
fill with form
information

Call CPutCartItem
to add new item to
shopping cart

Call
CGetCartDetails to
view shopping cart

Create a
DNAPayload and
load it with XML
returned from
CGetCArtDetails

Load XSL style


sheet into
DNAPayload

Write transformed
XML to browser as
HTML

End

FIGURE 17.16
The DNAPayload helps create the final HTML page.
PubsOnLine.com
440
PART V

The strategy used in the application allows the system to return browser-independent HTML. If
you were targeting only the Internet Explorer browser, you could return the XML directly and
simply apply the style sheet at the browser. In any case, changing the way the final page
appears is a matter of adjusting the XSL style sheet, which doesn’t require any changes to
source code. This approach effectively partitions the data from the display and provides
browser independence.

Deploying Components
Now that the source code for the project is complete, you are ready to compile the code and
deploy the components. Compiling must be done carefully to ensure that each project is made
correctly. Follow the steps below exactly.

EXERCISE 17.4

Compiling the Code and Deploying the Components

CAUTION
Because you started your project from the template directory, Visual Basic might
attempt to compile your project there. In the first step, check to make sure that you
compile in your project directory and not the template directory of Visual Basic.

Step 1
Begin with the Interfaces project. Compile this project into a DLL by selecting Make from the
File menu. After you compile the project, open the project properties dialog, change the version
compatibility to Binary Compatibility, and reference the DLL you just created. Then recompile
the project. This will guarantee that you correctly create a backward-compatible component.

Step 2
Repeat the process to compile the rest of the projects in the following order: Common,
DNAPayload, DataServ, and BizServ.

NOTE
Common problems that occur during this process include incorrect setting of the com-
patibility property and lost references to other projects in the system. Pay close atten-
tion to carefully setting compatibility and be prepared to resolve any missing
references in the project.
Building the PubsOnLine.com Application
441
CHAPTER 17

Step 3
After you successfully compile the COM+ components, you are ready to place them under
COM+ control. Before we add them to component services, however, we need to create an
account for the components to run under. This is accomplished inside the Active Directory.
Start the Active Directory Users and Computers applet inside this applet; select New and then
User from the Action menu. This will present a dialog to add the new user. Create an account
called COMPLUS with a password of compassword. Figure 17.17 shows the new user dialog
with the correct data filled in. After creating the user, you can add it to any necessary groups
to obtain appropriate permissions to run the COM+ applications under your particular config- 17
uration.

PUBSONLINE.COM
BUILDING THE
APPLICATION
FIGURE 17.17
Create an account for the COM+ application.

Step 4
Start the Component Services explorer. Begin by creating a new COM+ application named
POLEvents for the IWriteErrors event class. This class should go in a separate application so
that it can easily be used by any component in the system. Next, add the IWriteErrors class to
the application as an event class. Figure 17.18 shows the completed class under the COM+
application.

NOTE
Be sure to run all the COM+ applications under the COMPLUS account you created.
PubsOnLine.com
442
PART V

FIGURE 17.18
Create a COM+ application for the event class.

Step 5
Next, create a COM+ application for the CLogger class named POLLog. Then add the CLogger
class to this application. Once added, set up the CLogger class to subscribe to the events gener-
ated by the IWriteErrors event class. Figure 17.19 shows the completed class in component
services.

NOTE
If you have trouble setting up the subscription, see Chapter 9.

Step 6
Create one last COM+ application called POLServices. Add all the data and business compo-
nents to this application. Figure 17.20 shows the completed components.

Step 7
After the data and business classes are in a COM+ application, you must enable object con-
struction for each one. Each class uses a constructor string to find either the database, the Web
site, or the Active Directory. The constructor strings can vary for every installation, but Table
17.1 will give you an idea of how to create these strings. Figure 17.21 shows construction
enabled for a component.
Building the PubsOnLine.com Application
443
CHAPTER 17

17

PUBSONLINE.COM
BUILDING THE
APPLICATION
FIGURE 17.19
Log events by subscribing to IWriteErrors.

FIGURE 17.20
Add all the data and business classes to Component Services.
PubsOnLine.com
444
PART V

FIGURE 17.21
Enable construction for all data and business services.

TABLE 17.1 Construction Strings


Components Constructor
CBooks C:\inetpub\wwwroot\PubsOnLine
CCart
CMembership
DataServ.GetADSIAddress LDAP://machinename/
DataServ.GetADSIFriendlyName CN=,CN=Users,DC=domainname
DataServ.PutADSIAddress
All other DataServ classes Provider=SQLOLEDB;
Data Source=(local);
Initial Catalog=PubsOnLine;
UID=COMDATA;PWD=compassword

Now that the components are created and running under COM+, we have to create only the
Web site interface to the components. The Web site consists of ASP pages and XSL style
sheets. The ASP pages are used to call the COM+ components. The COM+ components
process the page requests and then write the results out to the browser. All of this makes for a
fairly simple Web site, as you’ll see.
Building the PubsOnLine.com Application
445
CHAPTER 17

Creating the Web Interface


In this section, you will create the Web site for the system. We won’t spend time writing code
here. Instead, we will build the new site and add the content from the CD-ROM. Once com-
pleted, we’ll examine some of the pages in the site.

EXERCISE 17.5

Creating the Web Site Interface 17

PUBSONLINE.COM
BUILDING THE
APPLICATION
Step 1
Start a new Web project in Visual InterDev. Be sure to name it PubsOnLine. You can set up
the project any way you want; however, when prompted for a theme, choose Bubbles (see
Figure 17.22). This theme is used by the various pages in the application.

FIGURE 17.22
Use the Bubbles theme with your Web site.

Step 2
After the Web project is created, you will need to add content from the CD-ROM to the pro-
ject. The Web pages can be located in the directory Project Templates\Chapter 17\Web.
Add all the files located in this directory to your project by selecting Add Item from the
Project menu. When the files are added, your project is complete. Before running the final
project, we’ll take a moment to examine some of the key pieces of the Web interface.
PubsOnLine.com
446
PART V

State management for the site is handled through a single cookie written to the client computer.
This cookie, named CARTNUM, is the unique identifier of the shopping cart. The cart identifier is
created when a customer logs in to the site and exists until the customer checks out. This
means that the customer’s session can exist even if he closes the browser and turns off his com-
puter. The cart contents are maintained in the database as shown earlier in this chapter.
Logins are handled by taking the username/password combination and verifying it against the
Active Directory. Therefore, you need to set up complete information about users before they
can log in to the site. Active Directory manipulation is handled by the CMembership business
class and three data classes that read and write to the directory.
After a successful login, the user will search for titles and add them to the cart. All input para-
meters are handled through forms or hyperlinks. Within the COM+ business classes, input
parameters are retrieved, packed into a DNAPayload, and delivered to data services. To under-
stand this process, we’ll examine how the system responds to a search request.
Users can search the site by filling out a simple HTML form. This form allows searches by
title, author, or publisher. There is nothing special about the form. It simply submits the data to
an ASP page named results.asp. The <FORM> tag is as follows:
<form METHOD=”POST” ACTION=”results.asp” id=form1 name=form1>

Things get interesting when we examine the results.asp page. In a standard ASP application,
this page would process the search request, but in our application, it hands off processing to the
business class CBooks. Because the processing is handled inside the COM+ component, the
ASP code is remarkably simple. The complete code for results.asp is as follows:
<%@ Language=VBScript %>
<!--#include file=”include/header.inc”-->
<%
Dim objBooks
Set objBooks = Server.CreateObject(“BizServ.CBooks”)
objBooks.Search
%>

One strong point of this design is that the ASP pages are so simple. For those of you who have
ever had a terrible experience trying to debug a complex ASP page, you will truly appreciate
this simplicity. With this simple page, however, you might be wondering how the search results
actually get displayed. This is accomplished by calling to the Response object from within
CBooks and using an XSL style sheet to transform the XML data to HTML. All the style sheets
can be found in the Web project under the XSL directory. The following simple code is
required to transform the search results into browser output where objReturn is an instance of
the DNAPayload and objContext is the COM+ context object:
Building the PubsOnLine.com Application
447
CHAPTER 17

objReturn.LoadXSL m_WebSite & “\xsl\results.xsl”


objReturn.XML2HTML
objContext(“Response”).Write objReturn.HTML
The idea of processing within the COM+ classes and using XSL style sheets permeates the
entire application design. This architecture provides an efficient, maintainable, partitioned sys-
tem that can be easily upgraded. If you’ve completed the project carefully, you should now be
able to run the site and order books.

17

PUBSONLINE.COM
BUILDING THE
APPLICATION
SYMBOLS
INDEX
@TRANSACTION=NOT SUPPORTED directive
(ASP), 291
@TRANSACTION=REQUIRED directive (ASP),
291
@TRANSACTION=REQUIRES NEW directive
(ASP), 291
@TRANSACTION=SUPPORTED directive
(ASP), 291

A
AbortRecordVariants method,
IcrmCompensatorVariants interface,
245-246
abstract classes, function signatures,
165-167
access credentials
database security, permissions, 117
pools, minimizing, 116-117
SQL Server logins, settings, 116
accessing
ASP objects with COM+ components, 298-299
objects, Active Direcory (LDAP), 216
stored procedures, business/user service layer
restrictions, 151
Web stores
ActiveX Data Objects (ADO) (Exchange
2000 Server), 334-337
through browsers (Exchange 2000 Server),
332-334
ACID
450

ACID (Atomicity, PubsOnLine.com Add Procedure command


Consistency, Isolation & Application, activating, (Tools menu), 50
Durability) 418 AdjustBalance method,
MSDTC functions, 183 replacement of Security transaction example,
transaction context, Accounts Manager 200-201
185-189 (SAM), 12 administering
Action menu commands, Schema explorer, 217 components (Component
New/Component, 46 secure logins, Services), 28-29
Activate method, OpenDSObject method, server privileges,
ObjectControl interface, 220 PubsOnLine.com
99-100 security, 12 Application, 418
activating objects, 88-90 features, 210 Administrator role, sys-
Quick Check exercise, group policies, 212 tem applications, 40
91-93 Microsoft Installer ADO (ActiveX Data
SetComplete method, (MSI), 211 Objects), 334-337
95-96 single sign-ons (SSO), Connection object, session
Activation tab 211 pooling, 114
(Component Services) user information, 212 Record object, 334-337
application properties, users Recordset object
36-38 authentication, 12 disconnected record-
component properties, 45 personalization, 12 sets, 129-130
Active Directory Active Server Pages, see GetString method,
(Windows 2000), 12, ASP 126-127
24-25 ActiveX controls, front- session pooling, 114
authentication of users, 12 end applications Stream object, 334-337
domain component (DC), creating, 319-320 streaming XML, 14,
215 event handling, 321-322 139-141
organization (O), 216 forms substitute, 320 Web stores
organizational unit lack of inheritance, 320 accessing (Exchange
(OU), 216 limitations of, 322 2000 Server), 334,
Domain Name Service loading, 319-324 337
(DNS), 25 ActiveX Data Objects, querying (Exchange
email manipulation, 12 see ADO 2000 Server),
enterprise database infor- actors 335-336
mation, 12 project design, 59-60 adOpenDynamic value
installing, 24-25 PubsOnLine application, (CursorType property),
LDAP, root, 214 identification, 393-394 124
pathnames, 213-214 adOpenForwardOnly
common name (CN), value (CursorType prop-
215 erty), 124
distinguished name
(DN), 215
ports, 214
applications
451

adOpenKeyset value apartments data services layer, deploy-


(CursorType property), components, synchroniza- ing, 357, 362
124 tion control, 85 design
adOpenStatic value multi-threaded (MTA), 85 actor identification,
(CursorType property), objects, concentric con- 59-60, 393-394
124 tainers, 84-88 artifacts, 58
ADSI (Active Directory single-threaded (STA), 85 component definition,
Services Interface), 213 thread-neutral (TNA), 85 415
authentication (Quick appending nodes, error database model, 407
Check 8-1 exercise), handling (XML), 161-163 functional require-
220-221 Application Center 2000, ments, assessment,
objects 369 55-58
properties, 216-219 Application object paper prototype, 403,
reference sets, 216-219 (Outlook 2000), 341 407
Advanced Server CreateItem method, 343 problem statements,
(Windows 2000), 11, 24 applications 54-55, 392
Advanced tab analysis tools Rational Unified
(Component Services) Component Load Process (RUP), 54
application properties, Balancing (CLB), 369 requirements, 392-393
38-39 Network Load screen shots, 403, 407
component properties, 46 Balancing (NLB), system models, 408-415
alternate application 367-368 Use Cases, 58-63,
proxy servers, exporting Web Application Stress 393-402
process, 30 tool (WAS), 363-367 development, evolution of,
alternate path event flow, business services layer, 84
Use Cases project deploying, 357-358, 362 distributed, 145-146
design, 64 client rich front-end distribution
alternate scenarios, Use ActiveX controls, application creation,
Cases project design, 63 319-322 370-371
analyzing applications custom collections, client software setups,
Component Load 314-315 360-361
Balancing (NLB), 369 VB forms, 312 group policies,
Network Load Balancing components, installing 361-362, 373-374
(NLB), 367-368 (COM Component Microsoft Installer
Web Application Stress Install Wizard), 46-48 (MSI), 357-359
tool (WAS), 363-367 creating (COM+ proxy setups, 359-360
Any Application role, sys- Application Install setups creation,
tem applications, 40 Wizard), 40-42 371-373
step-by step example, software installation,
49-51 375
applications
452

error handling (XML), Array( ) function, variant assertions, data compo-


161-163 arrays, 155-158 nents, 156
front end artifacts, project design, assessing functional
creating (Microsoft 58 requirements (project
Visual Modeler), as-soon-as-possible deac- design), 57-58
80-81 tivation, object memory asynchronous compo-
state layers, building, management, 17 nents, queued, 18
327-330 ASP (Active Server asynchronous processing,
group roles, 55 Pages), 290 256
HTA, 324 early scripting problems, components
deploying, 326 294-296 Microsoft Message
tags, 325-326 multi-page transactions, Queue (MSMQ),
IIS 5 creating, 292-294 256-257
in-process versus out- ObjectContext components queued components
of-process, 282 (IIS Utilities), 290 (QC), 256, 265-270
server isolation levels, @TRANSACTION= message queuing, 14
283-284 NOT SUPPORTED, atomicity, database trans-
MSMQ Object Model, cre- 291 action attribute, 182
ating, 258 @TRANSACTION= authentication
naming guidelines, 268 REQUIRED, 291 Active Directory
records, updating, 142-143 @TRANSACTION= Quick Check 8-1 exer-
recordset objects REQUIRES NEW, 291 cise, 220-221
complex data binding, @TRANSACTION= secure logins, 220
317-319 SUPPORTED, 291 DCOM, 31
simple data binding, objects Kerberos protocol
315-317 accessing with COM+ cloaking, 210
state support, 18 components, 298-299 tickets, 210
three-tier Request, 298-299 public key encryption,
data partitions, Response, 298-299 208-209
123-125 scriptless processing, 290 Security Support Provider
layers, 21-23 script classes, creating Interface (SSPI), 209
OOP, 23 (VBScript), 294-296 Windows NT LAN
tiered, creating (Exercise Server object Manager Security
4.1), 105-109 Execute method, Support Manager, 209
two-tier architecture, 19-21 292-294 automatic transactions,
user services layer, deploy- Transfer method, 18
ing, 359, 363 292-294 error handling, 195-198
ASPError object transactional components
GetLastError method, consistency bit,
286-288 192-198
properties, 286-288 done bit, 192-198
clients
453

B models (Microsoft Visual CCart class, ShowCart


Modeler), 70-81 method, 436-440
BackUpREGDB method, transactions, 199-204 CDO (Collaboration Data
COMAdminCatalog business services layer Objects), 336-337
object, 379 applications, deploying, certificates (security), 208
basic path event flow, 357-358, 362 Microsoft Management
Use Case project design, data components, 151 Console (MMC), snap-in
63 PubsOnLine.com additions, 209
batch files, writing, Application, creating, public key encryption,
383-384 436-440 208-209
BeginAbortVariants three-tier applications, champions
method, 21-23 functional requirements,
IcrmCompensator- transactional boundaries, assessment phase, 57-58
Variants interface, 189-190 group roles, project design,
245-246 byte arrays, property 55
BeginCommitVariants bags, returning, 133-134 choose tag (XSL), 305-306
method, class modules (Catalog
IcrmCompensator- Administration Wizard),
Variants interface, 387-388
245-246 C classes
BeginPrepareVariants events
calling queued compo-
method, defining, 233-234
nents (QC)
IcrmCompensator- installing, 234
new moniker, 268-270
Variants interface, 245 three-tier diagram, 69
queue moniker, 268-270
binary compatability, client-side transactions
CanBePooled method,
component debugging (QC), 271
ObjectControl interface,
(Visual Basic), 354-355 clients
99
BindingCollection object, applications
Catalog Administration
315-317 proxy setup, 359-360
class modules, wizard cre-
Body property software setup, 360-361
ation, 387-388
(MSMQEvent object), error handling messages,
Component Services
262-263 XML streams, 161-163
Administration Object
Boolean expressions, front-end applications
Model, 378
event filtering, 238 ActiveX controls,
COMAdminCatalog,
breakpoints, component 319-322
378-379
debugging (Visual custom collections,
COMAdminCatalogCol
Basic), 354 314-315
lection, 380-381
building VB forms, 312
COMAdminCatalogObj
corporate portals, 350-351
ect, 382-383
databases,
WSH, batch operation lan-
PubsOnLine.com
guages, 383-384
Application, 419-425
clients
454

HTA applications COM Component Install GetCollectionByQuery,


package deployments, Wizard, 48 379
326 event classes, installing, GetEventClassesForIID,
Web server deploy- 234 379
ments, 326 launching, 46 GetMultipleCompon-
cloaking (Kerberos proto- COM Internet Services, 32 entsInfo, 379
col), 210 COM+ (Component ImportComponent, 379
Cluster Parameters tab, Object Model) InstallApplication, 379
Network Load Balancing applications, developmen- InstallComponent, 379
(NLB), 368 tal evolution, 84 InstallEventClass, 379
coarse components services InstallMultipleCompon-
maintenance disadvan- application state sup- ents, 379
tages, 153 port, 18 QueryApplicationFile,
performance disadvan- asynchronous compo- 379
tages, 153 nents, 18 RefreshComponents,
transactional boundaries, automatic transactions, 379
186-189 18 RestoreREGDB, 379
versus fine-grain compo- event support, 17 ServiceCheck, 379
nents, 152 memory management, ShutdownApplication,
code generation 17 379
(Microsoft Visual multi-threaded apart- COMAdminCatalogCollec-
Modeler), 78-79 ments (MTA), 16-17 tion object
collaboration applications object pooling, 17 arguments, 380
Exchange 2000 Server security, 18 Applications, 380
email, 336-337 versus MTS in applica- Components, 380
Web stores, 332-337 tions development, 84 ComputerList, 380
Outlook 2000 COM+ Application Install DCOMProtocols, 380
data views, 338 Wizard, 40-42 ErrorInfo, 380
features, 338 COM+ Explorer, see InProcServers, 380
forms, 338-339 Component Services InterfacesForCompon-
Collaboration Data COM+ Services, Type ent, 380
Objects, see CDO Library, object context LocalComputer, 380
collisions communication, 93-96 MethodsForInterface,
causes, 143-144 COMAdminCatalog 380
disconnected recordsets, object, 378 PropertyInfo, 380
preventing, 142-143 methods, 379 PublisherProperties,
firehose cursors, prevent- BackUpREGDB, 379 380
ing, 142 Connect, 379 RelatedColectionInfo,
record updates, preventing, ExportApplication, 379 380
142-144 GetCollection, 379 Roles, 380
troubleshooting, 143-144
components
455

RolesforComponents, Component Services components


380 application properties administering (Component
RolesForInterface, 380 Activation tab, 36-38 Services), 28-29
RolesForMethod, 380 Advanced tab, 38-39 apartments, synchroniza-
Root, 380 General tab, 34 tion control, 85
SubscriberProperties, Identity tab, 36 application properties
381 Queuing tab, 38 (Component Services)
TransientSubscriptions, Security tab, 35 Activation tab, 36-38
381 component properties Advanced tab, 38-39
UsersInRole, 381 Activation tab, 45 General tab, 34
methods Advanced tab, 46 Identity tab, 36
GetCollection, 381 Concurrency tab, 46 Queuing tab, 38
Populate, 381 General tab, 43 Security tab, 35
commands Security tab, 44 applications, installing
Action menu, Transaction tab, 43 (COM Component Install
New/Component, 46 components Wizard), 46-48
Project menu, References, administration, 28-29 ASP objects, accessing,
51 listview, 29 298-299
Tools menu, Add treeview, 29 asynchronous processing
Procedure, 50 computer properties Microsoft Message
CommitRecordVariants Default Properties tab, Queue (MSMQ),
method, 30-32 256-257
IcrmCompensator- Default Protocols tab, queued components
Variants interface, 245 32 (QC), 256, 265-270
common name (CN), Default Security tab, 32 automatic transactions, 18
Active Directory path- General tab, 29 component properties
names, 215 MSDTC tab, 30 (Component Services)
communicating object My Computer Tasks Activation tab, 45
contexts, 93-96 tab, 33 Advanced tab, 46
Compensating Resource Options tab, 29-30 Concurrency tab, 46
Manager, see CRM launching, 28 General tab, 43
compiling source code transactional component Security tab, 44
(PubsOnLine.com properties, 184-185 Transaction tab, 43
Application), 440-442 user roles, 40 computer properties
complex binding, record- Component Services (Component Services)
set objects Administration Object Default Properties tab,
(DataBindingBehavior Model, 378 30-32
object), 317-319 roles, defining, 222 Default Protocols tab,
Component Load 32
Balancing (CLB), 369
components
456

Default Security tab, 32 Concurrency tab ContactItem object


General tab, 29 (Component Services (Outlook 2000), 345
MSDTC tab, 30 component property), context wrappers versus
My Computer Tasks 46 contexts, 85
tab, 33 conditional compilation, contexts
Options tab, 29-30 component debugging components
configured, 86-87 (Visual Basic), 355 configured, 86-87
constructors, passing, 239 conditions, use case pro- non-configured, 86-87
contexts versus context ject design, 62-63 GetObjectContext( ) func-
wrappers, 85 configured components, tion, 94-95
non-configured, 86-87 86-87 objects
PubsOnLine.com Connect method concentric containers,
Application (COMAdminCatalog 84-88
construction strings, object), 379 referencing, 93-96
444 Connection object (ADO), versus context wrappers,
creating, 425-428 session pooling, 114 85
deploying, 440-442 connection strings (MTS) controlling pools (OLEDB),
queued, 18 versus constructors, 238 115-117
state information, Shared consistency, database Controls collection
Property Manager transaction attribute, (Outlook 2000), 342
(SPM), 102-104 182 corporate portals (Web
threads consistency bit, transac- pages), 348-349
multi-thread apartment tional components, building, 350-351
(MTA), 16-17 192-198 corporate standards,
single-thread apartment construction strings polymorphism, develop-
(STA), 16-17 (PubsOnLine.com ing, 164
thread-neutral apart- Application), 444 CReadData template
ment (TNA), 16-17 constructors, 239 (Visual Basic),
transactional components, passing, 239 PubsOnLine.com
building, 199-204 IObjectConstruct interface, Application, 428-433
voting process, 190-195 239-240 Create Stream method,
Visual Basic IObjectConstructString XML output streams,
breakpoints, 354 object, 239-240 172-173
debugging, 354-355 Quick Check 9-1 exercise, CreateObject function
Visual InterDev, debug- 240-241 versus New keyword,
ging, 355 versus connection strings property bags, 131
concentric containers (MTS), 238 CreateObject method,
(objects) versus Shared Property WScript object (WSH),
apartments, 84-88 Manager (SPM), 238 384
contexts, 84-88 versus Universal Data
processes, 84-88 Link (UDL) files, 238
CWriteData template
457

CreateShortcut member, transactional Web pages transactions


Shell object (WSH), 385 (IIS 5), 290-294 isolation, 249
creating Web sites, success/failure voting
applications PubsOnLine.com process, 245
COM+ Application Application, 445-447 two-phase commit capabil-
Install Wizard, 40-42 CRM (Compensating ities, 242
MSMQ Object Model, Resource Manager), 242 Worker
258 duplicate log records, commit/abort actions,
step-by-step example, 249-252 242
49-51 flags (transactions), 244 designing, 242-243
business services layer IcrmCompensatorVariants durable logs, 242-243
(PubsOnLine.com interface transaction processing,
Application), 436-440 AbortRecordVariants 242
client software setups in method, 245-246 write-ahead operations,
applications, 360-361 BeginAbortVariants 244
components method, 245-246 CRMClerk object, 243
(PubsOnLine.com BeginCommitVariants ForceLog method, 244
Application), 425-428 method, 245-246 RegisterCompensator
data layer in distributed beginPrepareVariants method, 243-244
applications, 145-146 method, 245 cursors
data services layer CommitRecordVariants firehose, 125
(PubsOnLine.com method, 245 two-tier applications, 19
Application), 428-436 EndAbortVariants cursors (ADO), CursorType
event subscribers (New method, 245-246 property, 123
Subscription Wizard), EndCommitVariants adOpenDynamic value,
235-236 method, 245-246 124
group policies, application endPrepareVariants adOpenForwardOnly
deployment, 361-362 method, 245-246 value, 124
paper prototypes, Use PrepareRecordVariants adOpenKeyset value, 124
Cases project design, 65 method, 245 adOpenStatic value, 124
proxies in client-rich front- SetLogControlVariants custom collections, front-
end applications, 359-360 method, 245 end applications
queues (MSMQ Message Quick Check 9-2 exercise, (ICollection interface),
Queuing explorer), 257 247-249 314-315
standard function signa- Recovery In Progress customer information
tures (abstract classes), error, 249 repository (Active
165-167 system crashes, recovery Directory), 212
tiered applications, from, 249 CWriteData template
105-109 system-wide error logs, (Visual Basic),
creating, 249-252 PubsOnLine.com
Application, 433-436
data
458

D coarse, maintenance/per- data source proxy object,


formance disadvantages, see DPO
data 153 database models
data components data entities, 66
HTML display (DNA HTML display (DNA PubsOnLine application,
Payload), 174-175 Payload), 174-175 407
returning (DNA returning (DNA relationships, 66
Payload), 173-174 Payload), 173-174 databases
parsing (DNA Payload), transformation (DNA ACID attributes, 183
173-174 Payload), 167-169 batch updates, discon-
partitions, transporting DebugAssert( ) method, nected recordsets,
(three-tier applications), 156 142-143
123-125 design goals, 150 connections, session pool-
payloads, three-tier appli- encapsulation, 150-154 ing, 114
cations, 125-126 fine-grain, 152 distributed transactions,
transports function of, 150 two-phase commit, 183
delimited strings, parameters PubsOnLine.com
126-127 passing, 154-161 Application
disconnected record- passing (DNA creating, 419-425
sets, 129-130 Payload), 170-173 shopping carts, 419-
property bags, 131-134 stored procedures, 425
SOAP protocol, 141 repeated code, 152 records, collision preven-
Stream object (ADO), strong function signatures, tion, 142-144
139-141 154 rollback transactions, 182
three-tier applications, variant arrays, data, pass- transaction attributes
125-126 ing, 155-158 atomicity, 182
variant arrays, 127-128 XML parameters, passing, consistency, 182
XML, 134-138 158-161 durability, 182
data binding, recordset data device services layer, isolation, 182
objects three-tier applications, two-tier applications
BindingCollection object, 21-23 access, 19
315-317 data layer, distributed cursors, 19
DataBindingBehavior applications, creating, maintenance difficul-
object, 317-319 145-146 ties, 20-21
Data Center Server data services layer record locking, 19
(Windows 2000), 11 applications, deploying, scalability issues, 20
data components 357, 362 site design disadvan-
assertions, 156 fine-grain components tages, 20
business services layer, usage, 153
151 PubsOnLine.com
Application, creating,
428-436
distributed applications
459

DataBindingBehavior defining event classes, paper prototype, 403,


object, 317-319 233-234 407
Dataset object (DNA delimited strings problem statement, 392
Payload) characteristics, 126-127 requirements, 392-393
methods returning, 126-127 screen shots, 403, 407
LoadXSL, 174-175 XML, performance char- system models, 408-415
XML2HTML, 174-175 acteristics, 126 use cases, 393-402
properties, 169 deploying queued components (QC),
DCOM (Distributed COM), applications 266-268
30 business services layer, stored procedures, 151
authentication levels, 31 357-358, 362 digital dashboards, Web
firewalls, 32 data services layer, pages, 348-349
impersonation levels, 32 357, 362 digital signatures, public
Internet services, 32 user services layer, key encryption, 209
port usage, 32 359, 363 DirectCaller object, pro-
Deactivate method, components grammatic security, 225
ObjectControl interface, (PubsOnLine.com disconnected recordsets,
99-100 Application), 440-442 125
deactivating objects, HTA applications, 326 advantages, 134
88-90 designing batch updates, 142-143
SetAbort method, 95-96 applications characteristics, 129-130
DebugAssert( ) method, functional require- disadvantages, 134
156 ments, 55-58 record updates, 142-143
debugging components problem statements, returning, 129-130
Visual Basic, 354-355 54-55 DisconnectObject method,
Visual InterDev, 355 Rational Unified WScript object (WSH),
declarative security Process (RUP), 54 384
roles, access permissions, CRM Worker, 242-243 displaying data,
222 data components, goals, XML/HTML conversion
versus programmatic secu- 150 (DNA Payload), 174-175
rity, 226 projects distinguished name (DN),
Default Properties tab Actors, 59-60 Active Directory path-
(Component Services artifacts, 58 names, 215
computer property), Unified Modeling distributed applications
30-32 Language (UML), data layer, creating,
Default Protocols tab 59-60 145-146
(Component Services use cases, 58-60 polymorphism, standard-
computer property), 32 PubsOnLine application ization features, 163-164
Default Security tab actor identification, security, 208
(Component Services 393-394
computer property), 32 database model, 407
Distributed COM
460

Distributed COM, see documentation, use case enabling event sub-


DCOM project design, 60-61 scribers, 236
distributed transactions, domain component (DC), encapsulation
183 Active Directory, 215 data components, 150-154
distributing applications organization (O), 216 stored procedures
application creation, organizational unit (OU), class module example,
370-371 216 151
group policy creation, domain environments data components,
373-374 (MSMQ), 257 151-154
setups creation, 371-373 Domain Name Service EndAbortVariants
software installation, 375 (DNS), Active Directory, method,
dllhost.exe, processes, 25 IcrmCompensator-
object management, done bit, transactional Variants interface,
84-85 components, 192-198 245-246
DLLs (dynamic link DPO (data source proxy EndCommitVariants
libraries), installing, 48 object), 114 method,
DNA Payload pools, destruction of, IcrmCompensator-
data components 115-117 Variants interface,
data transformation, session pooling, 114 245-246
167-169 duplicate log records EndPrepareVariants
data, HTML display, (CRM), 249-252 method,
174-175 durability, database IcrmCompensator-
data, returning, transaction attribute, Variants interface,
173-174 182 245-246
parameters, passing, durable logs (CRM enterprise applications
170-173 Worker), 242-243 Active Directory, 12
Dataset object, 427-436 Network Load Balancing
methods, 170 (NLB), 16
properties, 169 scaling, 16
Field object, 427-436 E entities, database models,
parameters, passing, 66
e-commerce applications,
170 Environment member,
creating, 105-109
properties, 170 Shell object (WSH), 385
early bound events, 232
Recordset conversion, error handling
Echo method, WScript
171 automatic transactions,
object (WSH), 384
recordset, XML output 195-198
element tag (XSL), 306
stream, 172-173 XML nodes, appending,
email
returned streams 161-163
Exchange 2000 Server,
HTML display, 174-175 error logs, creating (CRM),
Collaboration Data
parsing, 173-174 249-252
Objects (CDO), 336-337
Outlook 2000, request
forms, creating, 346-348
front-end applications
461

error messages, Web email, Collaboration Data FinalClientRetry method,


pages, generating (IIS 5), Objects (CDO), 336-337 IPlaybackControl inter-
285-288 Web stores face (QC), 272
events ActiveX Data Objects FinalServerRetry method,
ActiveX controls, handlers, (ADO), 334-337 IPlaybackControl inter-
321-322 browser access, face (QC), 272
classes 332-334 fine-grain components
defining, 233-234 ExpandEnvironment- data services layer, 153
installing, 48 Strings member, Shell transactional boundaries,
interfaces, 233-234 object (WSH), 385 189-190
COM+ services, 17 ExportApplication versus coarse components,
early bound, 232 method 152
Item object (Outlook (COMAdminCatalog firehose cursors, 125
2000), 341-342 object), 379 record updates, 142
loosely coupled, 17 exporting applications XML, returning, 135-136
publishers, 232 client software setups, firewalls (DCOM), 32
subscribers, 232 360-361 firing events, 237
OnClick transaction exam- group policies, 361-362 flags, transactions (CRM),
ple, 203-204 Microsoft Installer (MSI), 244
publishers, 17 357-359 flow charts, use case pro-
firing, 237 proxy setups, 359-360 ject design, 64
subscribers, 17 eXtensible Markup Folders collection
creating (New Language, see XML (Outlook 2000),
Subscription Wizard), eXtensible Style GetDefaultFolder
235-236 Language, see XSL method, 344
enabling, 236 for-each tag (XSL), 305
filtering, 238 ForceLog method
implementing, 234-236 (CRMClerk object), 244
tightly bound, 232 F forms
exception path event ActiveX controls, design
facilitated sessions, pro-
flow, use case project of, 320
ject design require-
design, 64 client rich front-end appli-
ments, 56
exception scenarios, use cations, 312
Field object (DNA
case project design, 63 front-end applications
Payload)
exceptions (QC), 272 ActiveX controls
parameters, passing, 170
Exchange 2000 Server creating, 319-320
properties, 170
collaboration forms substitute,
Recordset conversion, 171
email, 336-337 320-322
filtering events in sub-
features, 332 lack of inheritance, 320
scriptions, 238
Web stores, 332-337 limitations of, 322
loading, 319-324
front-end applications
462

forms usage, 312 GetCollectionByQuery H-I


ICollection interface meth- method
ods, 314-315 (COMAdminCatalog handling events (ActiveX
Microsoft Visual Modeler, object), 379 controls), 321-322
80-81 GetDefaultFolder header sections, Use Case
state layers, building, method, constants project design, 61
327-330 (Outlook 2000), 344 Host Parameters tab,
state/workflow layer GetEventClassesForIID Network Load Balancing
(Win32 clients), 312-313 method (NLB), 368
function signatures (COMAdminCatalog HTA (HTML Application),
data components, parame- object), 379 324
ters, passing, 154 GetLastError method deploying, 326
Intellisense, 154 (ASPError object), tags, 325-326
standards, creating (poly- 286-288 HTML (Hypertext Markup
morphism), 165-167 GetMultipleComponents- Language) to XML trans-
functional requirements Info method formation, 136-138,
(project design) (COMAdminCatalog 174-175
assessing, 57-58 object), 379
facilitated sessions, 55-56 GetObject method, ICollection interface
prioritizing, 56-57 WScript object (WSH), methods
384 Add, 314-315
GetObjectContext( ) func- Count, 314-315
tion, 94-95 Item, 314-315
G GetString method, Remove, 314-315
Recordset object (ADO), IcrmCompensatorVariants
General tab (Component
126-127 interface
Services)
group policies AbortRecordVariants
application properties, 34
Active Directory, 212 method, 245-246
component properties, 43
client applications, creat- BeginAbortVariants
computer properties, 29
ing, 361-362 method, 245-246
generating custom error
groupware BeginCommitVariants
messages on Web pages
Exchange 2000 Server, method, 245-246
(IIS 5), 285-288
332 BeginPrepareVariants
GetBalance method,
email, 336-337 method, 245
transaction example,
Web stores, 332-337 CommitRecordVariants
201-202
Outlook 2000 method, 245
GetCollection method
data views, 338 EndAbortVariants method,
COMAdminCatalog
forms, 338-339 245-246
object, 379
EndCommitVariants
COMAdminCatalogCollect
method, 245-246
ion object, 381
EndPrepareVariants
method, 245-246
Item object
463

PrepareVariants method, Utilities package, ASP InstallMultipleCompon-


245 ObjectContext compo- ents method
SetLogControlVariants nents, 290-291 (COMAdminCatalog
method, 245 Windows DNA support, 12 object), 379
identifying impersonation levels instances
actors in system projects, (DCOM), 32 activation, 88-93
59-60 implementing event sub- deactivation, 88-90
functional requirements in scribers, 234-236 New keyword versus
project design, 55-57 ImportComponent CreateObject function,
Identity tab (Component method 131
Services application (COMAdminCatalog Intellisense, strong func-
property), 36 object), 379 tion signatures, 154
if tag (XSL), 305 in-process applications interfaces
IIS 5 (Internet Information versus out-of-process events classes, 233-234
Server version 5), 282 applications, 282 function signatures, stan-
applications in-process components, dardization of, 165-167
in-process versus out- unloading (IIS 5), 284 Internet Explorer, XML
of-process, 282 inheritance (ActiveX con- output, 14, 136
server isolation levels, trols), 320 Internet Information
283-284 Inspector object (Outlook Server version 5,
ASP errors, ASPError 2000), 342 see IIS 5
object, 286-288 InstallApplication method Internet services (DCOM),
COM+ integration, 282 (COMAdminCatalog 32
custom error messages, object), 379 IObjectConstruct inter-
generating, 285-288 InstallComponent method face, 239-240
HTTP errors, 285 (COMAdminCatalog IObjectConstructString
IIS Utilities package, trans- object), 379 object, 239-240
actional Web pages, 290 InstallEventClass method IPlaybackControl interface
in-process components, (COMAdminCatalog (QC), exception classes,
unloading, 284 object), 379 272
Internet Services Manager, installing isolated transactions
282 Active Directory, 24-25 (CRM), 249
Microsoft Management PubsOnLine.com isolating IIS applications,
Console (MMC) applica- Application, 418 server levels, 283-284
tion, 13 components in installa- isolation, database trans-
new features, 282 tions (COM Component action attribute, 182
previous versions, 282-283 Install Wizard), 46-48 Item object (Outlook
scriptless ASP processing, DLLs, 48 2000), 341-342
290 event classes, 48
transactional Web pages, COM Component
creating, 290-294 Install Wizard, 234
just-in-time activation
464

J-K-L M ImportComponent, 379


InstallApplication, 379
just-in-time activation MailItem object (Outlook InstallComponent, 379
(JIT), 17, 89-90 2000), 345-346 InstallEventClass, 379
maintenance in two-tier InstallMultipleCompon-
Kerberos protocol, 210 applications, 20-21 ents, 379
manual transactions, QueryApplicationFile,
launching transactional compo- 379
COM Component Install nents, 195 RefreshComponents,
Wizard, 46 marshaling variant 379
Component Services, 28 arrays, 127-128 RestoreREGDB, 379
LDAP (Lightweight memory, object manage- ServiceCheck, 379
Directory Access ment ShutdownApplication,
Protocol), 214 as-soon-as-possible deacti- 379
Active Directory, 214 vation, 17 COMAdminCatalogCollec-
objects, accessing, 216 just-in-time activation, 17 tion object
pathnames, 214 message queues, 263-264 GetCollection, 381
root, 214 asynchronous communica- Populate, 381
Lightweight Directory tions, 14 CreateStream, 172-173
Access Protocol (LDAP), methods Dataset object
12, 214 Activate, 99-100 LoadXSL, 174-175
Listener (QC), 266 AdjustBalance, transaction XML2HTML, 174-175
loading ActiveX controls example, 200-201 Dataset object (DNA
in front-end applica- Application object Payload), 170
tions, 319-324 (Outlook 2000), Deactivate, 99-100
LoadXSL method (Dataset CreateItem, 343 Debug Assert, 156
object), 174-175 ASPError object, ForceLog (CRMClerk
logical models GetLastError, 286-288 object), 244
goals, 67 CanBePooled, 99 GetBalance, transaction
patterns, 67 COMAdminCatalog object example, 201-202
UML, 68 BackupREGDB, 379 MSMQQueueInfo object
loosely coupled events Connect, 379 LookUpQueue, 259-260
(LCE), 17 ExportApplication, 379 Open, 260-261
publishers, 232 GetCollection, 379 Next, 260
subscribers, 232 GetCollectionByQuery, Reset, 260
379 polymorphism, 164
GetEventClassesForIID, RegisterCompoensator
379 (CRMClerk object),
GetMultipleCompon- 243-244
entsInfo, 379
MSMQMessage object
465

SetAbort, 95-96 modeling limitations, 264


SetComplete, 95-96 databases Object Model
Transfer, transaction exam- entities, 66 applications, creating,
ple, 202-203 relationships, 66 258
Microsoft Cluster Server logical model message/queue man-
versus NLB, 16 goals, 67 agement, 258
Microsoft Distributed patterns, 67 MSMQApplication
Transaction Coordinator, UML, 68 object, 258
see MSDTC Microsoft Visual Modeler, MSMQEvent object
Microsoft Installer (MSI) 70-81 WithEvents keyword,
Active Directory, 211 project design (UML), 261-262
applications, distribution, 59-60 MSMQMessage object
357-359 monikers (queued com- Body property, 262-263
Microsoft Management ponents) MSMQQuery object
Console (MMC) new, 268-270 LookUpQueue method,
certificates, snap-in addi- queue, 268-270 259-260
tions, 209 monitoring transactions MSMQQueueInfo
Internet Information Server (Component Services object
(IIS), 13 explorer), 198 Open method, 260-261
Microsoft Message MSDTC (Microsoft MSMQQueueInfos
Queue, see MSMQ Distributed Transaction object
Microsoft Transaction Coordinator), 183 Next method, 260
Server, see MTS transactional components Reset method, 260
Microsoft Visual Modeler Resource Dispensers, queues, creating (Message
applications, front end cre- 185 Queuing explorer), 257
ation, 80-81 Resource Managers, Quick Check 10-1 exer-
code generation, 78-79 185 cise, 263-264
logical models, creating, transactions, monitoring versus queued components
68 statistics, 198 (QC), 264
models, building, 70-81 two-phase commit, 183 MSMQApplication object,
objects MSMQ (Microsoft 258
classes, creating, 74-76 Message Queue), 14, 25, MSMQEvent object,
methods, creating, 256 WithEvents keyword,
74-76 asynchronous processing, 261-262
properties, creating, 256-257 MSMQMessage object,
74-76 benefits, 256 Body property, 262-263
reverse engineering, 71-73 domain environments, 257
round-trip engineering, installations, planning
71-73 guidelines, 256
MSMQQuery object
466

MSMQQuery object, New keyword versus objects


methods CreateObject function, activation, 88-90
LookUpQueue, 259-260 property bags, 131 Quick Check exercise,
Open, 260-261 new moniker (QC), 91-93
Next, 260 268-270 SetAbort method, 95-96
Reset, 260 New Subscription Wizard, SetComplete method,
MTS (Microsoft event subscribers, creat- 95-96
Transaction Server), 84 ing, 235-236 Active Directory, accessing
multi-page transactional New/Component com- (LDAP), 216
Web pages, creating mand (Action menu), 46 ADSI
(IIS 5), 292-294 nodes, appending (XML), properties, 216-219
multi-threaded apart- 161-163 reference sets, 216-219
ments (MTA), 16-17, 85 non-configured compo- as-soon-as possible deacti-
multi-valued properties, nents, 86-87 vation, 17
ADSI objects, 218-219 Catalog Administration,
My Computer Tasks tab 378
(Component Services COMAdminCatalog,
computer property), 33 O 378-379
COMAdminCatalogCol
Object Model (MSMQ)
lection, 380-381
MSMQApplication object,
COMAdminCatalogObj
N 258
ect, 382-383
MSMQEvent object,
classes, creating
NameSpace object WithEvents keyword,
(Microsoft Visual
(Outlook 2000), 343 261-262
Modeler), 74-76
naming applications, MSMQMessage object,
concentric containers
guidelines, 268 Body property, 262-263
apartments, 84-88
network cards, Network MSMQQuery object
contexts, 84-88
Load Balancing (NLB), LookUpQueue method,
processes, 84-88
367 259-260
contexts, referencing,
Network Load Balancing Open method, 260-261
93-96
(NLB) Next method, 260
deactivation, 88-90
activating, 367-368 Reset method, 260
DNAPayload
Cluster Parameters tab, object pooling, 17
Dataset class, 427-436
368 ObjectControl interface
Field class, 427-436
Host Parameters tab, 368 methods
instantiation, New key-
network cards, 367 Activate, 99-100
word versus
Port Rules tab, 368 CanBePooled, 99
CreateObject function,
versus Microsoft Cluster Deactivate, 99-100
131
Server, 16 Quick Check exercise,
100-101
parsing returned streams
467

just-in-time activation session pooling digital dashboards,


(JIT), 17, 89-90 benefits, 114 348-349
methods, creating implementing (Quick email request forms exer-
(Microsoft Visual Check exercise), cise (Quick Check 13-2),
Modeler), 74-76 120-122 346-348
ObjectControl interface Registry tuning, object model
Activate method, 117-120 Application object, 341
99-100 OnClick event, transac- CreateItem method, 343
CanBePooled method, tion example, 203-204 ContactItem object, 345
99 Online Flower Shop (QC) Controls collection, 342
Deactivate method, data components creation, Folders collection, 344
99-100 275-276 Inspector object, 342
Quick Check exercise, database creation, 273-274 Item object, 341-342
100-101 email component creation, MailItem object, 345-
274-275 346
polymorphism, 164 Web site creation, 277-278 NameSpace object, 343
processes (dllhost.exe), Online Shopping Cart Page object, 342
84-85 (XSL) TaskItem object, 345
properties, creating cart database creation, VBScript, 340-341
(Microsoft Visual 306-307 Visual Basic, 340-341
Modeler), 74-76 components creation, 307
property bags, 131 Web site creation, 307-309
byte arrays, returning, OOP (object-oriented pro-
133-134 gramming), 23 P
persistence, 132 OpenDSObject method,
packages, HTA applica-
stateful, 98 secure logins (Active
tions, deploying, 326
stateless, 96-98 Directory), 220
Page object (Outlook
transaction context, OriginalCaller object, pro-
2000), 342
185-189 grammatic security, 225
paper prototypes
transactional components, out-of-process applica-
PubsOnLine application,
184-185 tions versus in-process
403, 407
WSH (Windows Scripting applications, 282
Use Case project design,
Host) Outlook 2000
65
Shell, 385 collaboration
parameters, data compo-
WScript, 384-385 data views, 338
nents, passing (DNA
XML, returning, 135-136 forms, 338-339
Payload), 170-173
OLEDB (Object Linking corporate portals, 348-349
parsers (XML), 140
and Embedding building, 350-351
parsing returned streams
Database)
(DNA Payload), 173-174
pools, controlling, 115-117
providers, searching
(REGEDIT utility),
117-120
partitions
468

partitions, three-tier pools (OLEDB) Professional Workstation


applications, 21-23, access credentials, 116 (Windows 2000), 11
123-125 database security, 117 programmatic security
passing logins, 116 DirectCaller object, 225
constructors to compo- SQL Server logins, 116 OriginalCaller object, 225
nents, 239 controlling, 115-117 SecurityCallContext
parameters in data compo- Populate method object, 223-225
nents (DNA Payload), (COMAdminCatalogColl SecurityIdentity object,
170-173 ection object), 381 226
query parameters in data Popup member, Shell versus declarative security,
components, 154-161 object (WSH), 385 226
pathnames (Active Port Rules tab, Network Project menu commands,
Directory), 213-214 Load Balancing (NLB), References, 51
common name (CN), 215 368 projects
distinguished name (DN), post-conditions, use case design
215 project design, 62-63 Actors, 59-60
ports, 214 pre-conditions, use case artifacts, 58
patterns, logical model, project design, 62-63 functional require-
67 PrepareRecordVariants ments, 55-58
payloads method, problem statements,
data sets, three-tier appli- IcrmCompensator- 54-55
cations, 125-126 Variants interface, 245 three-tier diagram, 69
schema definitions, 126 prioritizing functional Unified Modeling
XML, 158-161 requirements in project Language (UML),
perfect scenarios, use design, 56-57 59-60
case project design, 63 problem statements use cases, alternate
Performance Monitor, ses- project design, 54-55 path event flow, 64
sion pooling, 117 PubsOnLine application, use cases, alternate
persistence, property bag 392 scenarios, 63
objects, 131-134 procedure calls, cross- use cases, basic path
platforms, procedure calls platform (SOAP), 141 event flow, 63
(SOAP), 141 processes use cases, conditions,
player (QC), 266 dllhost.exe, object man- 62-63
polymorphism agement, 84-85 use cases, documenting,
corporate standards, devel- objects, concentric con- 60-61
oping, 164 tainers, 84-88 use cases, exception
function signatures, stan- path event flow, 64
dardizing, 165-167 use cases, exception
standardization features, scenarios, 63
163-164
QC (queued components)
469

use cases, flow charts, proxy servers, exporting DNAPayload object


64 process, 30 Dataset class, 427-436
use cases, header sec- public key encryption Field class, 427-436
tions, 61 digital signatures, 209 paper prototype, 403, 407
use cases, paper proto- private keys, 208-209 problem statement, 392
types, 65 public keys, 208-209 requirements, 392
use cases, perfect sce- publishers membership and per-
narios, 63 events, firing, 237 sonalization, 393
use cases, purpose loosely coupled events promotions, 393
statements, 62 (LCE), 232 site analysis, 393
use cases, rules, 62-63 PubsOnLine.com screen shots, 403, 407
group roles, 55 Application source code, compiling,
logical modeling actors 440-442
goals, 67 Administrator, 393-394 system models, 408
patterns, 67 Customer, 393-394 three-tier, 408-415
UML, 68 business services layer, use cases, 393-394
properties creating, 436-440 Add Book to Cart,
ADSI objects CCart class, ShowCart 397-399
multi-valued, 218-219 method, 436-440 Checkout, 401-402
single-valued, 218-219 components Log In, 394-396
Dataset object (DNA construction strings, View Cart, 399-400
Payload), 169 444 Visual Basic
Field object (DNA creating, 425-428 CReadData template,
Payload), 170 deploying, 440-442 428-433
WScript object (WSH), data services layer, creat- CWriteData template,
385 ing, 428-436 433-436
property bags database Web site, creating, 445-447
byte arrays, returning, creating, 419-425 purpose statements, use
133-134 shopping carts, case project design, 62
characteristics, 131-134 419-425
New keyword versus database model, 407
CreateObject functions, development environments
131 Active Directory acti- Q
object properties manage- vation, 418
QC (queued components),
ment, 132 administrator privi-
18, 256
proxies, client-rich front leges, 418
calling
end applications, creat- SQL Server, 418
via new moniker,
ing, 359-360 Visual Basic, 418
268-270
Visual InterDev, 418
via queue moniker,
268-270
QC (queued components)
470

design guidelines, 266-268 Queuing tab (Component Recordset object (ADO)


exception classes Services application disconnected recordsets,
FinalClientRetry, 272 property), 38 129-130
FinalServerRetry, 272 Quick Check exercises methods, GetString,
Listener, 266 constructors (9-1), 126-127
Online Flower Shop exer- 240-241 session pooling, 114
cise CRM (9-2), 247-249 recordset objects
data components cre- email request forms complex data binding,
ation, 275-276 (13-2), 346-348 317-319
database creation, message queues (10-1), disconnected, 125
273-274 263-264 output streams, creating
email component cre- simple components (10-2), (CreateStream method),
ation, 274-275 270-271 172-173
Web site creation, transactional Web pages simple data binding,
277-278 (11-2), 297-298 315-317
Player, 266 Web stores, accessing Recovery in Progress error
Recorder, 265-266 (13-1) (Exchange 2000 (CRM), 249
transactions Server), 337 reference sets (ADSI),
client-side, 271 WSH application shut- 216-219
server-side, 272 downs (15-3), 386-387 References command
versus Microsoft Quit method, WScript (Project menu), 51
Messaging Queue object (WSH), 384 referencing objects, con-
(MSMQ), 264-265 texts, 93-96
QC Trusted User role, 40 RefreshComponents
query parameters, data method
components, passing, R (COMAdminCatalog
154-161 object), 379
Rational Unified Process,
QueryApplicationFile RegDelete member, Shell
see RUP
method object (WSH), 385
Reader role, system appli-
(COMAdminCatalog REGEDIT utility, OLEDB
cations, 40
object), 379 providers, searching,
Record object (ADO),
querying Web stores, 117-120
334-337
ActiveX Data Objects RegisterCompensator
record-locking, two-tier
(ADO), 335-336 method (CRMClerk
applications, 19
queue moniker, 268-270 object), 243-244
Recorder (QC), 265-266
queued components, see Registry, session pooling,
records, collision preven-
QC tuning, 117-120
tion, 142-144
queues, creating (MSMQ RegRead member, Shell
Message Queuing object (WSH), 385
explorer), 257 RegWrite member, Shell
object (WSH), 385
sending email
471

relationships, database rollbacks, transaction fail- Kerberos protocol


models, 66 ures, 182 cloaking, 210
repeated code alterna- root templates, XSL style tickets, 210
tives, 152 sheets, 302-304 programmatic
coarse components, round-trip engineering DirectCaller object,
152-153 (Microsoft Visual Visual 225
fine-grain components, 152 Modeler), 71-73 OriginalCaller object,
Request object (ASP), rules, Use Case project 225
298-299 design, 62-63 SecurityCallContext
Resource Dispensers Run member, Shell object object, 223-225
(MSDTC), 185 (WSH), 385 SecurityIdentity object,
Resource Managers RUP (Rational Unified 226
(MSDTC), 185 Process), 54 versus declarative, 226
Response object (ASP), Security Support Provider
298-299 Interface (SSPI), 209
RestoreREGDB method server impersonations, 208
(COMAdminCatalog S strategies, 226
object), 379 Visual InterDev, compo-
scalability
returning nent debugging, 355
enterprise applications, 16
byte arrays from property Windows 2000, Active
two-tier applications, 20
bags, 133-134 Directory, 210-212
Schema explorer (Active
data in data components Windows NT LAN
Directory), 217
(DNA Payload), 173-174 Manager Security
screen shots, PubsOnLine
delimited strings, 126-127 Support Provider
application, 403, 407
disconnected recordsets, (NTLMSSP), 209
script classes (ASP), creat-
129-130 Security Support Provider
ing (VBScript), 294-296
variant arrays, 127-128 Interface (SSPI), 209
searching OLEDB
XML Security tab (Component
providers (REGEDIT util-
from COM+ objects, Services)
ity), 117-120
135-136 application properties, 35
security
from Stream object component properties, 44
Active Directory, 12
(ADO), 139-141 SecurityCallContext
COM+ services, 18
reverse engineering object, programmatic
declarative
(Microsoft Visual Visual security, 223-225
roles, 222
Modeler), 71-73 SecurityIdentity object,
versus programmatic,
roles programmatic security,
226
declarative security, access 226
distributed applications
permissions, 222 self-defined payloads, 126
certificates, 208
programmatic security, sending email,
famous breaches, 208
223-225 Collaboration Data
Objects (CDO), 336-337
Server Applications role
472

Server Applications role, SetLogControlVariants simple binding,


system applications, 40 method, BindingCollection
Server object (ASP) IcrmCompensator- object, 315-317
Execute method, 292-294 Variants interface, 245 Simple Object Access
Transfer method, 292-294 setting server isolation Protocol (SOAP), 141
server-side transactions levels (IIS 5), 283-284 single sign-ons (SSO),
(QC), 272 Shared Property Manager Active Directory, 211
servers (SPM) single-threaded apart-
administrator privileges application state support, ments (STA), 16-17, 85
(PubsOnLine.com 18 single-valued properties,
Application), 418 object hierarchy, 102 ADSI objects, 218-219
impersonation, security SharedProperty, 103 SOAP (Simple Object
breaches, 208 SharedPropertyGroup, Access Protocol), 141
ServiceCheck method 102 software, client applica-
(COMAdminCatalog SharedPropertyGroup tions, creating, 360-361
object), 379 Manager, 102 source code, compiling
session pooling (OLEDB), Quick Check exercise, (PubsOnLine.com
114 103-104 Application), 440-442
access credentials, 116 stateful components, man- SpecialFolders member,
database security, 117 agement of, 102-104 Shell object (WSH), 385
logins, 116 versus constructors, 238 SQL Server (Windows
SQL Server logins, 116 SharedProperty object 2000), 26
benefits, 114 (SPM), 103 database, creating
system size criteria, SharedPropertyGroup (PubsOnLine.com
120 object (SPM), 102 Application), 419-425
database connections, 114 SharedPropertyGroup- SQL statements versus
DPO, 114 Manager object (SPM), stored procedures, 151
formulaic calculations, 102 stakeholders
115-117 Shell object (WSH) mem- functional requirements,
implementing (Quick bers, 385 assessment phase, 57-58
Check exercise), 120-122 shopping carts, group roles, 55
tracking (Performance PubsOnLine.com PubsOnLine application,
Monitor), 117 Application, 419-425 392
tuning (Registry), 117-120 ShowCart method, CCart membership and per-
SetAbort method, object class (PubsOnLine.com sonalization, 393
deactivation, 95-96 Application), 436-440 promotions, 393
SetComplete method, ShutdownApplication site analysis, 393
object activation, 95-96 method standards, function signa-
(COMAdminCatalog tures, creating (polymor-
object), 379 phism), 165-167
three-tier applications
473

state layers, applications, style sheets (XML), T


building, 327-330 136-138
state support, Shared style sheets (XSL) tags
Property Manager tags, 301 HTA attributes, 325-326
(SPM), 18 templates, 302-304 XML syntax, 301
state/workflow layer, subscribers, events XSL
front-end applications creating (New choose, 305-306
(Win32 clients), 312-313 Subscription Wizard), element, 306
stateful objects, 98 235-236 for-each, 305
Shared Property Manager enabling, 236 if, 305
(SPM), 102-104 filtering, 238 style sheets, 301-304
stateless objects, 96-98 implementing, 234-236 value-of, 305
stored procedures loosely coupled events TaskItem object (Outlook
access restrictions, busi- (LCE), 232 2000), 345
ness/user services layers, system application roles templates
151 (Component Services) transactional Web pages
data components Administrator, 40 (IIS 5), 291-292
encapsulation, 151-154 Any Application, 40 XSL style sheets, 302-304
repeated code, 152 QC Trusted User, 40 test environments, estab-
design, 151 Reader, 40 lishing, 24-26
encapsulation, class mod- Server Applications, 40 testing applications
ule example, 151 system crashes, recovery Component Load
versus SQL statements, 151 from (CRM), 249 Balancing (CLB), 369
storyboards, see paper system modeling Network Load Balancing
prototypes databases (NLB), 367-368
Stream object (ADO), entities, 66 Web Application Stress
334-337 relationships, 66 tool (WAS), 364-367
data schema section, 139 logical model thread-neutral apart-
XML, returning, 139-141 goals, 67 ments (TNA), 16-17, 85
streams (XML), 14 patterns, 67 threads
client error handling, UML, 68 multi-threaded apartment
161-163 three-tier diagram, 69 (MTA), 16-17
creating (CreateStream PubsOnLine applica- single-threaded apartment
method), 172-173 tion, 408-415 (STA), 16-17
parameters, passing, system-wide error logs, thread-neutral apartment
160-161 creating (CRM), 249-252 (TNA), 16-17
strong function signatures three-tier applications
data components, parame- classes
ters, passing, 154 business services, 69
Intellisense, 154 data services, 69
versus variant arrays, 155 user services, 69
three-tier applications
474

creating (Exercise 4.1), transactional boundaries monitoring (Component


105-109 business services layer, Service explorer), 198
data 189-190 QC
partitions, 123-125 coarse data components, client-side, 271
payloads, 125-126 186-189 server-side, 272
transports, 125-126 design, 187-189 rollbacks, 182
data transports fine-grained components, Transfer method, transac-
delimited strings, 189-190 tion example, 202-203
126-127 transactional components transforming data compo-
disconnected record- automatic transactions nents (DNA Payload),
sets, 129-130 consistency bit, 167-169
property bags, 131-134 192-198 transports
variant arrays, 127-128 done bit, 192-198 data sets in three-tier appli-
layers, separations, 21-23 error handling, cations, 125-126
OOP, 23 195-198 delimited strings, 126-127
PubsOnLine application, mutually exclusive disconnected recordsets,
408-410 options, 184-185 129-130
Add Book to Cart use Resource Dispensers, 185 advantages, 134
case, 412-414 Resource Managers, 185 disadvantages, 134
Checkout use case, voting process property bags, 131-134
414-415 automatic, 190-195 SOAP protocol, 141
component definition, manual, 190, 195 Stream object (ADO),
415 transactional Web pages XML data, returning,
Log In use case, building (Quick Check 139-141
410-411 11-2 exercise), 297-298 variant arrays, 127-128
tickets (Kerberos proto- creating (IIS 5), 290-294 XML, 134-138
col), 210 multi-page, creating troubleshooting colli-
tiered architecture (IIS 5), 292-294 sions, 143-144
(Windows DNA), 10 transactions tuning Registry settings,
tightly bound events, 232 attributes (ACID), 182 session pooling 117-120
Tools menu commands, building, 199-204 two-phase commit
Add Procedure, 50 CRM commit, 183
transaction context, flags, 244 CRM, 242
185-187, 189 isolation, 249 distributed transactions,
transaction processing success/failure voting 183
(CRM Worker), 242 process, 245 prepare, 183
Transaction tab distributed, two-phase two-tier applications
(Component Services commit, 183 cursors, 19
component property), maintenance difficulties,
43 20-21
Visual Basic
475

record-locking, 19 header sections, 61


V
scalability issues, 20 perfect scenarios, 63
site design disadvantages, prototypes, 65 value-of tag (XSL), 305
20 purpose statements, 62 variant arrays
typical diagram, 19 rules, 62-63 characteristics, 127-128
PubsOnLine application, data components, data,
393-394 sending, 155-158
Add Book to Cart, Debug Assert( ) method,
U 397-399 156
Checkout, 401-402 disadvantages, 155
UDA (Universal Data
Log In, 394-396 marshaling process,
Access), 14
View Cart, 399-400 127-128
UML (Unified Modeling
user services layer returning, 127-128
Language)
applications, deploying, versus strong function sig-
Actor symbols, 59-60
359, 363 natures, 155
logical model, 68
three-tier applications, versus XML, 158
use case symbols, 59-60
21-23 VBControlExtender
Unified Modeling
users object, WithEvents key-
Language, see UML
Active Directory, informa- word, 321-322
Universal Data Access
tion tracking, 12 VBScript
(UDA), 14
enterprise applications, ASP pages, script classes,
Universal Data Link (UDL)
scaling, 16 294-296
files versus constructors,
roles Outlook 2000 object
238
Administrator model, 340-341
unloading in-process com-
(Components Visual Basic
ponents (IIS 5), 284
Services), 40 applications, developmen-
updating records, collision
Any Application tal evolution, 84
prevention, 142-143
(Components components
use cases
Services), 40 creating
project design, 58-60
declarative security, (PubsOnLine.com
alternate path event
222 Application), 425-428
flow, 64
QC Trusted User debugging, 354-355
alternate scenarios, 63
(Components CReadData template
basic path event flow,
Services), 40 (PubsOnLine.com
63
Reader (Components Application), 428-433
conditions, 62-63
Services), 40 CWriteData template
documenting, 60-61
Server Applications (PubsOnLine.com
exception path event
(Components Application), 433-436
flow, 64
Services), 40
exception scenarios, 63
flow charts, 64
Visual Basic
476

debugging performance counters, Web stores (Exchange


binary compatability, 365-367 2000 Server), 332-337
354-355 testing process, 364-367 Win32, front-end applica-
breakpoints, 354 Web browsers, Exchange tions, state/workflow
conditional compila- 2000 Server layer, 312-313
tion, 355 Web stores access, Windows 2000
events 332-337 Active Directory, 24-25
early bound, 232 Web stores queries, group policies, 212
tightly bound, 232 335-336 LDAP protocol, 12
Outlook 2000 object Web pages Microsoft Installer
model, 340-341 ASP scriptless processing (MSI), 211
property bags, 131-134 (IIS 5), 290 security features, 210
PubsOnLine.com corporate portals (Outlook single sign-ons (SSO),
Application, 418 2000), 348-351 211
Visual InterDev, 26 custom error messages, user information, 212
debugging, access restric- generating (IIS 5), Advanced Server, 24
tions, 355 285-288 Internet Information Server
PubsOnLine.com digital dashboards (IIS), 12, 25
Application, 418 (Outlook 2000), 348-349 Kerberos protocol authen-
Web site creation, transactional tication, 210
445-447 building (Quick Check Microsoft Message Queue
Visual Studio, 26 11-2 exercise), (MSMQ), 25
Installer, client software 297-298 Network Load Balancing
setup, 360-361 creating (IIS 5), (NLB), 16
voting transactional com- 290-294 services
ponents Web servers, HTA applica- Advanced Server, 11
automatic, 190-195 tions, deploying, 326 Data Center Server, 11
manual, 190, 195 Web sites Professional
success/failure process Active Directory, user per- Workstation, 11
(CRM), 245 sonalization, 12 Standard Server, 11
e-commerce applications, SQL Server, 26
creating, 105-109 XML Document Object
PubsOnLine.com Model (DOM), 14
W Application, creating, Windows Distributed
445-447 interNet Application
Web Application Stress
two-tier applications, 2000, see Windows DNA
tool (WAS)
maintenance difficulties, Windows DNA (Windows
application analysis, 363
20-21 Distributed interNet
downloading, 363
Application 2000), 10, 14
interface, 364
XSL
477

Windows NT, LAN HTML pages, data trans- XML data, associations,
Manager Security formation, 136-138 300-301
Support Provider 209 Internet Explorer XML transformation to
Windows Scripting Host, output, 136 HTML, 136-138
see WSH support, 14
WithEvents keyword parsers, 140
(MSMQEvent object), payloads, 158-161
261-262 returing from Stream
write-ahead operations Object (ADO), 139-141
(CRM Worker), 244 streaming, 14
writing parameters, passing,
batch files (WSH), 160-161
383-384 style sheets, 136-138
problem statements, pro- tags, syntax, 301
ject design, 54-55 versus variant arrays, 158
Wscript object (WSH) XSL style sheets, associa-
methods 384 tions, 300-301
properties, 385 XML Document Object
WSH (Windows Scripting Model (DOM), 14
Host), 383-384 XML2HTML method
application shutdowns (Dataset object),
(Quick Check exercise 174-175
15-3), 386-387 XSL (eXtensible Style
batch operation languages, Language), 136-138, 300
383-384 Online Shopping Cart
objects cart database creation,
Shell, 385 306-307
WScript, 384-385 components creation,
307
Web site creation,
307-309
X-Y-Z style sheets
tags, 301
XML (eXtensible Markup
templates, 302-304
Language), 14, 134, 300
XML processing
COM+ objects, returning,
instructions, 300-301
135-136
tags
data components, parame-
choose, 305-306
ters, passing, 158-161
element, 306
delimited strings, self-
for-each, 305
defined, 126
if, 305
value-of, 305
What’s on the CD
The companion CD-ROM contains all of the authors’ source code and samples from the book
and some third-party software products.

Windows 95, Windows 98, Windows NT 4, and


Windows 2000 Installation Instructions
1. Insert the CD-ROM into your CD-ROM drive.
2. From the desktop, double-click the My Computer icon.
3. Double-click the icon representing your CD-ROM drive.
4. Double-click the icon titled START.EXE to run the installation program.
5. Follow the onscreen instructions to finish the installation.

NOTE
If Windows 95, Windows 98, Windows NT 4, or Windows 2000 is installed on your
computer, and you have the AutoPlay feature enabled, the START.EXE program starts
automatically whenever you insert the disc into your CD-ROM drive.

Read This Before Opening This Software


By opening this package, you are agreeing to be bound by the following agreement:
You may not copy or redistribute the entire CD-ROM as a whole, Copying and redistribution
of individual software programs on the CD-ROM is governed by terms set by individual copy-
right holders.
The installer and code from the author(s) are copyrighted by the publisher and the author(s).
Individual programs and other items on the CD-ROM are copyrighted or are under GNU
license by their various authors or other copyright holders.
This software is sold as-is without warranty of any kind, either expressed or implied, including
but not limited to the implied warranties of merchantability and fitness for a particular pur-
pose. Neither the publisher nor its dealers or distributors assumes any liability for any alleged
or actual damages arising from the use of this program. (Some states do not allow for the
exclusion of implied warranties, so the exclusion may not apply to you.)

Das könnte Ihnen auch gefallen