Scot Hillier’s COM+ Programming with Visual Basic

®

Scot Hillier

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

Copyright
FIRST EDITION

©

2000 by Sams Publishing

ASSOCIATE PUBLISHER
Bradley L. Jones

All rights reserved. No part of this book shall be reproduced, stored in a retrieval system, or transmitted by any means, electronic, mechanical, photocopying, recording, or otherwise, without written permission from the publisher. No patent liability is assumed with respect to the use of the information contained herein. Although every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions. Neither is any liability assumed for damages resulting from the use of the information contained herein. For information, address Sams Publishing, A division of Macmillan Computer Publishing, 201 W. 103rd St., Indianapolis, IN 46290. International Standard Book Number: 0-672-31973-X Library of Congress Catalog Card Number: 00-102598 Printed in the United States of America First Printing: September 2000 03 02 01 00 4 3 2 1

ACQUISITIONS EDITOR
Sharon Cox

DEVELOPMENT EDITOR
Susan Shaw Dunn

MANAGING EDITOR
Charlotte Clapp

PROJECT EDITOR
Paul Schneider

COPY EDITOR
Rhonda Tinch-Mize

INDEXER
Chris Barrick

PROOFREADER
Kimberly Campanello

Interpretation of the printing code: the rightmost double-digit number is the year of the book’s printing; the rightmost single-digit, the number of the book’s printing. For example, a printing code of 98-1 shows that the first printing of the book occurred in 1998. Composed in Function Condensed, AGaramond and MCPdigital by Macmillan Computer Publishing

TECHNICAL EDITOR
Rick Anderson

TEAM COORDINATOR
Meggo Barthlow

SOFTWARE SPECIALISTS
William Eland, Jr. Dan Scherf

Trademarks
All terms mentioned in this book that are known to be trademarks or service marks have been appropriately capitalized. Sams Publishing cannot attest to the accuracy of this information. Use of a term in this book should not be regarded as affecting the validity of any trademark or service mark.

INTERIOR DESIGNER
Anne Jones

COVER DESIGNER
Aren Howell

Warning and Disclaimer
Every effort has been made to make this book as complete and as accurate as possible, but no warranty or fitness is implied. The information provided is on an “as is” basis. The author and the publisher shall have neither liability nor responsibility to any person or entity with respect to any loss or damages arising from the information contained in this book or from the use of the CD or programs accompanying it.

LAYOUT TECHNICIANS
Ayanna Lacey Heather Hiatt Miller Stacey Richwine-DeRome

Contents at a Glance
Part I 1 2 3 4 Part II 5 6 7 Part III 8 9 10 Part IV 11 12 13 14 15 Part V 16 17 Understanding COM+ Applications Windows DNA and COM+ Administering COM+ 27 53 83 9

Designing COM+ Applications

COM+ Application Fundamentals Data Services Accessing Data with COM+ COM+ Data Components COM+ Transactions Business Services COM+ Security 207 231 181 113

149

COM+ Business Features

Asynchronous COM+ Applications User Services COM+ and the Internet COM+ and Win32 311 281

255

Integrating COM+ with Groupware

331 353

Debugging and Deploying COM+ Applications COM+ Catalog Administration PubsOnLine.com Designing the PubsOnLine.com Application Building the PubsOnLine.com Application Index 449 377

391 417

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
1

UNDERSTANDING COM+ APPLICATIONS

7

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 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 DESIGNING COM+ APPLICATIONS 53 Assessing Functional Requirements ......................................................54 Problem Statement............................................................................54 Gathering Requirements ..................................................................55 Assessing Requirements ..................................................................57

2

3

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 DATA SERVICES 111

PART II
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
6

WITH

VISUAL BASIC

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 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 BUSINESS SERVICES 205

7

PART III
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

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 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 USER SERVICES 279

vii

10

PART IV
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 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 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 COM+ CATALOG ADMINISTRATION 377 The COM+ Administration Object Model ..........................................378 The COMAdminCatalog Object ....................................................378 The COMAdminCatalogCollection Object................................380 The COMAdminCatalogObject Object ........................................382

13

14

15

CONTENTS
Performing COM+ Administration with the Windows Scripting Host....................................................................................383 The WScript Object........................................................................384 The Shell Object ............................................................................385

ix

PART V
16

PUBSONLINE.COM

389

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 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

17

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 juggling 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 readable. 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 certainly 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, disagreements, 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 message. 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: Email: Mail: (317) 581-4770
adv_prog@mcp.com

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 partitioning 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+ applications. 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 successfully 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 features. 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 connections 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 transactions within your COM+ application. You’ll find out how the Distributed Transaction Coordinator (DTC) provides strong transactional control and how to access it from

INTRODUCTION

3

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 components. 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 programmatic 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 transactional 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 information 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 mechanism 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 alternatives 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 programmatic 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 quantifying 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 interface 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 documentation for the application built in the next chapter. It also presents the application development lifecycle you should follow.

INTRODUCTION

5

• 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 various pieces of information and to make them easily recognizable:

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

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

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.

Understanding COM+ Applications

PART

I

IN THIS PART
1 Windows DNA and COM+ 2 Administering COM+ 27 53 83 9

3 Designing COM+ Applications

4 COM+ Application Fundamentals

Windows DNA and COM+

CHAPTER

1

IN THIS CHAPTER
• Windows 2000 Services 11 18 23 • Tiered Architecture Overview

• Establishing a Test Environment

10

Understanding COM+ Applications 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 architecture 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 concepts, 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 positioning of .NET relative to COM+ as it’s currently being defined. Keep in mind, however, 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+ CHAPTER 1

11

Microsoft.NET is intended to be a framework that allows developers to create Webbased applications that integrate different Internet services regardless of the platform 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 crossplatform 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.

1
WINDOWS DNA AND COM+

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; however, 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 packaged 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 architecture as Windows DNA.

12

Understanding COM+ Applications 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 enterprise. 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 virtually any resource on the enterprise. Active Directory can be used to catalog enterprise printers, 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 directory 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 administrator’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 ecommerce, 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 enhancements for developers utilizing ASP and client-side scripting. These new features are covered in Chapter 11, “COM+ and the Internet.”

Windows DNA and COM+ CHAPTER 1

13

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.

14

Understanding COM+ Applications 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 processing 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 information. 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+ CHAPTER 1

15

Connection Errors Properties Command Parameters Properties Recordset Fields Properties Record Fields Stream Field Field Property Parameter Property Error Property

1
WINDOWS DNA AND COM+

FIGURE 1.3
ADO 2.5 supports several new features and objects.

FIGURE 1.4
Internet Explorer has built-in support for XML.

16

Understanding COM+ Applications 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 specific 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 component 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+ CHAPTER 1

17

MTA components, however, is that they suffer from restrictions on just which threads are allowed to run in the component. TNA components solve this problem by supporting any available thread at any time. 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 support only the STA model. Microsoft has indicated that Visual Basic will support the TNA model under version 7.0.

1
WINDOWS DNA AND COM+

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 created 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 without 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 optimized. For this reason, lack of object pooling features won’t significantly affect your application’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+ component to receive events fired by another. In and of itself, this might not seem like a new feature.

18

Understanding COM+ Applications PART I

After all, Visual Basic has supported the Event keyword for some time. COM+ events, however, 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 failure 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 components. 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 components 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 discussed 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 architectural philosophy is slow to penetrate the Visual Basic community. In early 1999, Deb Kurata

Windows DNA and COM+ CHAPTER 1

19

was still teaching fundamental object-oriented programming at the VBITS conferences, and it was still one of the best received talks long after everyone was supposed to have known the information cold. With that in mind, I present the fundamentals of tiered architecture. If you are already familiar with this discussion, you’ll want to move on.

1
WINDOWS DNA AND COM+

Two-Tier Architecture
Two-tier architecture is the most common and well-understood approach to database applications. In this model, the display of data is tightly bound to the storage of the data in the database. 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 application 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 Information Server

SQL 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.

20

Understanding COM+ Applications PART I

Under many Internet applications, cursors have become less of an issue because Internet development inherently drives correct use of database connections. For an application to scale properly, 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 application 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 procedures. If the database structure is changed or the stored procedure is altered, it will undoubtedly 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 experience. 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 endlessly 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+ CHAPTER 1

21

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

1
WINDOWS DNA 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 architecture. 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 intermediate 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.

22

Understanding COM+ Applications PART I

COM+ Components

XML Pages User Services

Internet Information Server Business Services

SQL Server 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 statements, 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 applications 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 technologies 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+ CHAPTER 1

23

Creating a three-tier application is, of course, significantly more complicated than a two-tier application. Right away you have to deal with designing and creating distributed components that run remotely. Also, the machines that make up the business services are shared among 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 programming 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 significant 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 constitutes one of the main goals.

1
WINDOWS DNA AND COM+

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 understanding of everyday architectural issues surrounding distributed application design and development. Before you begin, you’ll want to establish a test environment where you can easily work all the projects.

24

Understanding COM+ Applications PART I

Windows 2000 Advanced Server
Windows 2000 forms the backbone of our test environment. Although you can work with different 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 confusing 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+ CHAPTER 1

25

During the promotion process, you will be prompted to set up the Domain Name Service (DNS). DNS allows computer names to be resolved to TCP/IP addresses. Active Directory requires this service to operate correctly. Although the setup will make appropriate DNS 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.

1
WINDOWS DNA AND COM+

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.

26

Understanding COM+ Applications 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
28

IN THIS CHAPTER
• The Component Services Explorer

28

Understanding COM+ Applications 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 computer 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+ CHAPTER 2

29

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 selecting 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 description can be as long as 500 characters. Figure 2.2 shows the General tab.

2
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 transactions 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 recommended 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.

30

Understanding COM+ Applications PART I

FIGURE 2.3
The Options tab.

Along with the transaction timeout, the Options tab allows you to specify an alternate application 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+ systems 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+ CHAPTER 2

31

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 determines 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 services of a distributed component. The authentication level settings enable authentication at various levels based on how tightly you want to control security. Table 2.1 lists the available settings and explains their effect. TABLE 2.1 Setting Default None Connect Call Packet Packet Integrity Packet Privacy
DCOM Authentication Levels

Explanation Use the default security settings for the application. No authentication is performed. Callers are authenticated only when they first connect to a component. Callers are authenticated each time they access a method of a component. Each data packet is authenticated. Authenticates each packet and ensures that no packet data has been modified during transmission. Authenticates each packet, ensures that no packet data has been modified during transmission, and encrypts the data.

32

Understanding COM+ Applications 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 Setting Anonymous Identify Impersonate Delegate
Impersonation Level Settings

Explanation The caller can’t be identified. The component can impersonate the caller for identification purposes only. The component can impersonate the caller to access system resources. 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 communicate 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+ CHAPTER 2

33

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 perform 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

34

Understanding COM+ Applications 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 environment for COM+ components, which allows COM+ to provide services. This one-to-one mapping 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 rightclicking and selecting Properties from the pop-up menu. The first tab you will see on the property sheet is the General tab, which contains the name and description of the COM+ application.

Administering COM+ CHAPTER 2

35

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 administrative tasks programmatically. In Chapter 15, “COM+ Catalog Administration,” I discuss programmatic administration. Figure 2.8 shows the General tab.

2
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.

36

Understanding COM+ Applications 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 person 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 components. We normally set up an account with just the minimum number of permissions necessary 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 applications run in a copy of dllhost.exe, whereas library applications run in the client application’s memory space.

Administering COM+ CHAPTER 2

37

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 application, 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.

38

Understanding COM+ Applications 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 component 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 programmatically 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 control many aspects of how the COM+ application behaves. The first setting you can affect determines 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+ CHAPTER 2

39

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. COM+ provides support for automatic transactions that you can use to create transactional systems. 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.

2
ADMINISTERING COM+

FIGURE 2.13
The Advanced tab.

40

Understanding COM+ Applications PART I

The System Application
Earlier, I alluded to designating administrators for Component Services. Setting up administrative 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 Role Administrator Any Application QC Trusted User Reader Server Application
System Application Roles

Permissions Modifies configurations and components. Contains all usernames utilized for application identity for both library and server applications. Sends messages for queued components on behalf of other users. Has read-only access to Component Services. 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+ CHAPTER 2

41

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 earlier, 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.

42

Understanding COM+ Applications 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, components have property settings that you can change. To access the property sheet for any component, simply right-click the component and select Properties from the pop-up menu. The property sheet will then appear.

Administering COM+ CHAPTER 2

43

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, parent 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

44

Understanding COM+ Applications 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 functionality 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+ CHAPTER 2

45

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.

2
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 activated by COM+. This string can be anything. It might be a flag indicating that a generic component 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 feature 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.

46

Understanding COM+ Applications PART I

The Concurrency Tab
The Concurrency tab on the component property sheet allows you to specify the synchronization 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 message. 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+ CHAPTER 2

47

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 examining 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 previously installed a component from a DLL and now need to add a new class from the same DLL to a different application.

48

Understanding COM+ Applications 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+ CHAPTER 2

49

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 relationship 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 dialog 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.

50

Understanding COM+ Applications 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 signature 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+ CHAPTER 2

51

DLL will be listed in the Add Components dialog. Click Next and then Finish to add the component 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. Step 14 As a simple example of calling a COM+ component, we will just create an instance of the 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)

2
ADMINISTERING COM+

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 • Describing the System 58 65 54

• Creating the Paper Prototype

54

Understanding COM+ Applications 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 mentality 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 modeling 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 specification, 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 programmers, 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 requirements. 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 CHAPTER 3

55

Key Principle
A problem statement focuses on the business problem to be solved, not the technology 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, developers 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. This statement can’t be made lightly. The exact percentage will have to be approved at a high level of management. This will cause discussion among company management that will attract 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.

3
DESIGNING COM+ APPLICATIONS

Gathering Requirements
Once the problem statement is written, you are ready to create a list of functional requirements. 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 development 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

56

Understanding COM+ Applications 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 succeed 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 development 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 simple 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 CHAPTER 3

57

Priority A B C

Definition Absolutely required Enhances the product 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 Function Personalization and Membership
Prioritized Requirements

Ranking A

Description Users should be able to personalize, create wish lists, and use shopping carts. Users should be able to search by various keys and navigate the site based on these keys. Site should offer coupons and email announcements. We need to understand how promotional activities result in sales. Users should be able to review books online.

3
DESIGNING COM+ APPLICATIONS

Search and Navigation Improvements Promotional Enhancements Usage Analysis Online Reviews

A

A B C

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 champion 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.

58

Understanding COM+ Applications 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 feature on the prioritized list. A domain expert is someone highly knowledgeable in the requirements 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 eliminate project enemies from the process. Everyone had a chance to be heard at the initial meeting, 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 document 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 stakeholders 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 CHAPTER 3

59

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 initially identifying use cases, limit them to simple one-line phrases. Later, you will expand the detail in each use case, but for now you are trying to create a system outline based on the actors and use cases. Naming actors and use cases takes practice, but remember that an actor interacts with the system to receive a value. The use case is a functional name of the value received. A simple example 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 blueprints 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 models. 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

3
DESIGNING COM+ APPLICATIONS

60

Understanding COM+ Applications 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 earlier. 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 parties. Just like the facilitated sessions I discussed earlier, the interview process requires experience 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 departments are notified, and other key pieces of information.

Designing COM+ Applications CHAPTER 3

61

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 information. 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.

3
DESIGNING COM+ APPLICATIONS

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:

62

Understanding COM+ Applications 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, editing, and deleting records in a database, or would you create just one? Answers to these questions 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 CHAPTER 3

63

• 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 deal gracefully with errors. What happens if the username and password are wrong? What if the credit card isn’t valid? 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

3
DESIGNING COM+ APPLICATIONS

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.

64

Understanding COM+ Applications 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.

[ No ]

Does user have a cookie? [ Yes ]

Enter User Name and Password

[ No ] Are User Name and Password Authentic? [ Yes ]

Is cookie valid? [ Yes ]

[ No ]

User Name Cookies written to client. Logged In

FIGURE 3.4
Use flow charts to help describe the flow of events.

Designing COM+ Applications CHAPTER 3

65

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 system. 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 throw them away. The correct way to create a paper prototype is with a drawing program like Visio, or better yet, paper and pencil. You want the user to feel that the screens are easily changed and only represent a concept that can be modified. You’ll create a full set of screens as you envision the system. 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 software that goes behind the screens.

3
DESIGNING COM+ APPLICATIONS

66

Understanding COM+ Applications 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 understood of all system models. In nearly all projects, even poorly designed ones, some kind of database 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 CHAPTER 3

67

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 logical 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 single 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 achieving success. To use current trendy terminology, you need a pattern. A pattern is a predefined solution to a problem. Although every software development project 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 information. 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.

3
DESIGNING COM+ APPLICATIONS

68

Understanding COM+ Applications 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 function 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 software will be complete. When I present this concept of designing down to the method level, different people have various 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 people 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 blueprints 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 properly 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 CHAPTER 3

69

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 diagram. 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>> order.asp (from ASP) <<Class Module>> CCart (from Cart) <<Class Module>> CPutOrder (from Cart) <<Class Module>> CPutCartItem (from Cart) <<Class Module>> CDeleteCartItem (from Cart) <<Class Module>> CCreateCart (from Cart) <<Class Module>> CGetCartDetails (from Cart) <<Class Module>> CUpdateCart (from Cart)

<<Active Server Page>> contents.asp (from ASP)

<<Active Server Page>> home.asp (from ASP) <<Class Module>> CMembership (from Membership)

<<Class Module>> CPutADSIAAddress (from Membership) <<Class Module>> CPutADSIAddress (from Membership)

3
DESIGNING COM+ APPLICATIONS

<<Active Server Page>> validate.asp (from ASP)

<<Active Server Page>> shipping.asp (from ASP)

<<Class Module>> CGetADSIFriendlyName (from Membership)

<<Active Server Page>> results.asp (from ASP) <<Class Module>> CBooks (from Books)

<<Class Module>> CGetBookDetails (from Books)

<<Class Module>> CGetTitlesByPublisher (from books) <<Class Module>> CGetTitlesByAuthor (from books)

<<Active Server Page>> details.asp (from ASP)

<<Class Module>> CGetTitlesByTitle (from Books)

FIGURE 3.8
Three-tier diagrams help developers understand a system.

70

Understanding COM+ Applications 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 CHAPTER 3

71

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. 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 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.

3
DESIGNING COM+ APPLICATIONS

FIGURE 3.10
Select to create a new model.

72

Understanding COM+ Applications PART I

NOTE
Sometimes when you reverse engineer a form, Visual Modeler will give an error stating 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 CHAPTER 3

73

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 Finish to build the model. When the wizard is finished, you will see a component labeled frmClient in the user services layer. 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.

3
DESIGNING COM+ APPLICATIONS

FIGURE 3.13
Select to add to the existing model.

74

Understanding COM+ Applications PART I

Step 16 This time, work your way through the wizard, but make the DataClass object part of the business 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 component 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 CHAPTER 3

75

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
DESIGNING COM+ APPLICATIONS

Step 21 In the Options dialog (see Figure 3.16), you can create new sets of property procedure attributes. 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.

76

Understanding COM+ Applications PART I

Step 22 The Child set now is a clone of the default set. In the characteristics list, change the following characteristics: New Generate Get Operator Generate Set Operator True True 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 CHAPTER 3

77

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 to Process by typing directly into the list in which the new method appears. Set the return type of the method to Long by using the drop-down list. Click OK to close the specification dialog. Figure 3.19 shows the completed method definition.

3
DESIGNING COM+ APPLICATIONS

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

Step 27 Save the model.

78

Understanding COM+ Applications 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 definitions 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 CHAPTER 3

79

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 click Finish to generate your code. Step 34 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 information 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

3
DESIGNING COM+ APPLICATIONS

80

Understanding COM+ Applications 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 CHAPTER 3

81

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 Form Label TextBox CommandButton Label ProgressBar Property
Caption Name Caption Name Text Name Caption Name Caption Name

Setting
Memory Usage lblMachine Machine Name txtMachine

3
DESIGNING COM+ APPLICATIONS

Leave empty
cmdGO GO! lblLoad Memory Load 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

82

Understanding COM+ Applications 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 Fundamentals

CHAPTER

4
84 102

IN THIS CHAPTER
• Understanding Contexts • Object Activation 88

• Managing Shared Properties

84

Understanding COM+ Applications 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 problem 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 thousands 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 integrates 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 development of a distributed system architecture.

Understanding Contexts
COM+ has many features and can be described from many different perspectives, but the simplest 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 CHAPTER 4

85

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 access to a component is critical for synchronization, the management of thread access to an object’s methods for the purpose of preventing collisions between the threads (see Figure 4.2). If threads were allowed unrestricted access, one thread could easily corrupt the values of variable 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.

4
COM+ APPLICATION FUNDAMENTALS

86

Understanding COM+ Applications PART I
Apartment Object Instance

Thread Pool

Apartment 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 components are generally created in the context of the calling client. Figure 4.4 shows how configured and non-configured components are placed in a context.

COM+ Application Fundamentals CHAPTER 4

87

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 component. One supposed advantage of having the object’s context as an integral part of the operating system 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()

4
COM+ APPLICATION FUNDAMENTALS

88

Understanding COM+ Applications 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 CHAPTER 4

89

through variable scope. The best solution to instance management is to allow COM+ to automatically 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 property 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 process the method call. The beauty of this scheme, however, is that the client is unaware that an object instance is created or destroyed. Only COM+ needs to know whether the object has 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.

4
COM+ APPLICATION FUNDAMENTALS

90

Understanding COM+ Applications 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 simply 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 CHAPTER 4

91

have discovered that deactivation doesn’t always occur correctly—particularly if your component 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).

4
COM+ APPLICATION FUNDAMENTALS

FIGURE 4.7
Activation is already enabled.

92

Understanding COM+ Applications 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 CHAPTER 4

93

Notice that even though your front end has done nothing, a single instance has been activated. This is somewhat unexpected because JIT activation implies that the object is created 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+ components. 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 dialog. The reference should be set from within the ActiveX DLL project that will become your business object. Figure 4.10 shows the references dialog box in Visual Basic.

4
COM+ APPLICATION FUNDAMENTALS

FIGURE 4.10
Set a reference to the COM+ Services Type Library.

94

Understanding COM+ Applications 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 business 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 variable 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 template 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 CHAPTER 4
App.LogEvent Err.Description, vbLogEventTypeError Resume MyFunctionExit End Function

95

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
This dialog box writes template COM+ code for you.

4
COM+ APPLICATION FUNDAMENTALS

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.

96

Understanding COM+ Applications 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 implementation, 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 feature, it stands to reason that the client can’t rely on the values of any variables within the component 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 CHAPTER 4

97

transaction unto itself. All these design requirements are dictated by COM+’s activation/deactivation 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 module named Customer. The Customer class contains only a single property for the customer’s name. 4. Compile the DLL project and close Visual Basic. 5. Create a new COM+ application in the Component Services explorer named State. Install the compiled component into the new COM+ application. 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 restrictions as a browser. If you double-click the file, it will run as shown in Figure 4.13.

4
COM+ APPLICATION FUNDAMENTALS

98

Understanding COM+ Applications 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 better 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 CHAPTER 4

99

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 pooling 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 version 7.0. Objects that implement the CanBePooled method will easily take advantage of pooling 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 apartment 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
COM+ APPLICATION FUNDAMENTALS

The Activate and Deactivate methods are much more useful and interesting than the 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.

100

Understanding COM+ Applications PART I

By using these methods, you can perform special work when your object is activated or deactivated as well as track the life of the object. Activation and deactivation are tracked on a perclient 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 window. 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 CHAPTER 4
Private Sub ObjectControl_Deactivate() App.StartLogging App.Path & “\pool.log”, vbLogToFile App.LogEvent “COM+ Test Object Deactivated!” End Sub

101

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. 13. After you set up the package and component, run the frontend.hta file by double-clicking 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.

4
COM+ APPLICATION FUNDAMENTALS

102

Understanding COM+ Applications 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, developers 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
is created through the use of the CreatePropertyGroup method of the 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.
SharedPropertyGroup SharedPropertyGroupManager

COM+ Application Fundamentals CHAPTER 4

103

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 property, 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. The following code shows the function definition as it exists when you open the project:
Public Function GetUserNumber() As String ‘Variables Dim blnExists As Boolean ‘***Start Adding Code Here!*** ‘Return Value GetUserNumber = “You are client no. “ & objProperty.Value End Function

4
COM+ APPLICATION FUNDAMENTALS

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.

104

Understanding COM+ Applications 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 specify 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 whenever 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 CHAPTER 4

105

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 project files. Step 2 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:

4
COM+ APPLICATION FUNDAMENTALS

106

Understanding COM+ Applications 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 CHAPTER 4

107

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 building 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.

4
COM+ APPLICATION FUNDAMENTALS

FIGURE 4.17
Give the new Web application a name.

108

Understanding COM+ Applications PART I

Step 10 The next two wizard steps ask if you want to apply a layout or a theme. Layouts supply navigational 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 identified within the template:
Response.Write Response.Write Response.Write Response.Write “<SCRIPT>” & vbCrLf “var customerID = “ & lngCustomerID & “;” & vbCrLf “var quantity = 0;” & vbCrLf “</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 CHAPTER 4
function order(){ var myParent = document.frames.parent myParent.frames(“Cart”).navigate _ (“order.asp?ID=” + myParent.customerID _ + “&Quantity=” + myParent.quantity); }

109

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
A simple store that uses COM+ components.

COM+ APPLICATION FUNDAMENTALS

Data Services

PART

II

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

Accessing Data with COM+

CHAPTER

5

IN THIS CHAPTER
• OLEDB Session Pooling 114 123 • Understanding Data Transportation • XML 134 142

• Updating Records

114

Data Services 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+ applications. 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 manage 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 connection 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 diagram of this process.

Accessing Data with COM+ CHAPTER 5

115

Internet Client Internet Client ActiveX Data Objects Win32 Client All clients are coded as if they each had a unique connection.

DPO objects exist in 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 connection 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. Controlling the number of pools used by the system is critical to the overall efficiency of the 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.

5
ACCESSING DATA WITH COM+

116

Data Services 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 credentials 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 characteristics 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 single account in Active Directory for our COM+ components. This account is given just the permissions 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 standard 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+ CHAPTER 5

117

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 connections 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 particular 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 Provider. This will turn up all the entries for the OLEDB providers installed on your system. Figure 5.5 shows REGEDIT and the search dialog box.

5
ACCESSING DATA WITH COM+

118

Data Services 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+ CHAPTER 5

119

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 services, 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 argument 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 WITH COM+ FIGURE 5.6
Add the SPTimeout setting to tune session pooling.

120

Data Services PART II

Selecting an appropriate value for the timeout depends on the number of users in your application and how many pools are created. The whole point of session pooling is to avoid the overhead 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 timeout value to be twice the average time between database connections. If a client hits the database 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 overhead 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+ CHAPTER 5

121

7. Now locate the file client.hta. This file calls the COM+ component and requests database 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.

122

Data Services 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 indicate 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+ CHAPTER 5

123

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 moving from the theoretical to the practical lies in understanding how the various tiers will communicate 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 conceptual drawing of data being transported between the data and business services tiers.
Business Services Data Services

3. The "container" is unpacked so the data can be operated on.

2. The "container is transported from one layer to the next.

1. Individual records from the database must be 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 cursors. Creating the correct cursor is a matter of setting the proper combinations for the CursorLocation, CursorType, LockType, and CacheSize properties. If you are unfamiliar with the various cursors supported by ADO, you will have difficulty designing applications that perform well. The following sections examine the values for the CursorType property, followed by appropriate settings for the other properties.

5
ACCESSING DATA WITH COM+

124

Data Services 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 easily 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+ CHAPTER 5

125

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 create 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
CursorLocation CursorType LockType CacheSize

Value
adUseServer adOpenForwardOnly adLockReadOnly 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 advantage 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
CursorLocation CursorType LockType

Value
adUseClient adOpenStatic adLockBatchOptimistic

Understanding Transports and Payloads
To communicate the concepts inherent in moving data sets around a tiered system, we define two new terms: transport and payload. A transport is the container inside of which we pack 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 contains a payload.

5
ACCESSING DATA WITH COM+

126

Data Services 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 selfdefined 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+ CHAPTER 5

127

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 returned to the calling client when the function completed. 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

5
ACCESSING DATA WITH COM+

128

Data Services 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+ CHAPTER 5
Public Enum ArrayFieldsEnum SSN FirstName LastName Address City State Zip End Enum

129

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 selfdefinition. 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 marshaling 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 contains are converted into a special format known as Advance Data Tablegram (ADTG). This format 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 information provided by the Fields collection make this transport very attractive. The drawback 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.

5
ACCESSING DATA WITH COM+

130

Data Services 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 disassociate 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 recordset. 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+ CHAPTER 5

131

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 customer, order, and supplier objects. Because you can actually pass objects that represent business 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 application and replaced New with CreateObject. My experience, on the other hand, is that well designed distributed systems generally have no need to create instances of 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.

5
ACCESSING DATA WITH COM+

132

Data Services 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 associated 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 manage 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+ CHAPTER 5

133

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 ‘Put object in Property Bag Set objBag = New PropertyBag objBag.WriteProperty “Author”, objAuthor

5
ACCESSING DATA WITH COM+

134

Data Services 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 application 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 limited 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 information 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+ CHAPTER 5

135

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) & _ “text/xsl” & Chr$(34) & “ href=” & Chr$(34) & _ “data.xsl” & Chr$(34) & “?>” & vbCrLf strTemp = strTemp & “<PUBLISHERS>” & vbCrLf & “<NAME>”

5
ACCESSING DATA WITH COM+

136

Data Services 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 associated 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+ CHAPTER 5

137

FIGURE 5.11
Simple XML in the Internet Explorer.

5
ACCESSING DATA WITH COM+

FIGURE 5.12
Simple XML with a style sheet.

138

Data Services PART II

After you associate the XML with a style sheet, you can use the style sheet to change the rendering of the XML. The XSL page conforms to XML rules. The style sheet is really a specialized 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 publishers 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 bottom of the sheet where a new table row is created for each publisher’s name. In this way, an

Accessing Data with COM+ CHAPTER 5

139

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 component 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 filename, 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 ‘Return XML Stream GetData = m_Stream.ReadText End Function

5
ACCESSING DATA WITH COM+

140

Data Services 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 performance. 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 document, 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 proponent 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 representation of the data. This is the best of all possible scenarios.

Accessing Data with COM+ CHAPTER 5

141

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 format 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 outlined 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 new Web Services feature. Web Services are essentially classes that know how to open a SOAP request and process it. The key thing to understand about SOAP is that it compliments my discussion on transports and payloads. It doesn’t replace it.

5
ACCESSING DATA WITH COM+

142

Data Services PART II

Updating Records
Regardless of the transport mechanism you use, you still have to find a way to update the database 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 building. 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 information 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 successfully implement this system is much higher than the first example.
DELETE,

When you use firehose cursors, updates are normally performed by building SQL UPDATE, 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 conflict with changes made by a previous user. The code in Listing 5.9 shows how a COM+ component might receive a recordset as an argument and perform an update on the database.

Accessing Data with COM+ CHAPTER 5

143

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 current 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 update a field in a record that someone else has already updated. In this case, the OriginalValue isn’t the same as the UnderlyingValue.

5
ACCESSING DATA WITH COM+

144

Data Services 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 concurrency controls as cursor applications. However, most of these collisions aren’t critical in a runof-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 collisions 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 conflicting 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 values 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 timestamp 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 applications, 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+ CHAPTER 5

145

EXERCISE 5.1 Creating a Data Layer
The first step in understanding distributed applications is learning to contain data access functions 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 resulting 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 ‘Get Records Dim m_Recordset As ADODB.Recordset

ACCESSING DATA WITH COM+

146

Data Services 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+ CHAPTER 5

147

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 written 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 following 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+

148

Data Services PART II

FIGURE 5.13
The records are formatted as HTML.

COM+ Data Components

CHAPTER

6
151

IN THIS CHAPTER
• Encapsulating Stored Procedures • Parameter Passing • Error Handling 161 163 154

• Polymorphic Interfaces • The DNA Payload • Conclusion 175 167

150

Data Services 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 services 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 encapsulation 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 component 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 CHAPTER 6

151

Encapsulating Stored Procedures
The data services layer consists of a set of components that encapsulate Structured Query 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 procedure 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 database 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 database, 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 Date out Authors Table

6
COM+ DATA COMPONENTS

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

152

Data Services 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 Data Component Data Component

Data Component Data Component Data Component

stored procedure stored procedure stored procedure stored procedure stored procedure stored procedure stored procedure

Business Component

Business Component

Data Component

Business Services Layer

Data Services 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 something 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 commonly used alternative architecture.

COM+ Data Components CHAPTER 6
Parameters and stored procedure name as input Dataout

153

6
One large component performing all data access

COM+ DATA COMPONENTS

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 strategy 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 performance 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 system must reside in the same application. This is a dangerous requirement because an administrator 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.

154

Data Services 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 different versions of ADO could possibly require a significant amount of work, but my solution suffers 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 component.

Strong Function Signatures
The most common technique for sending data into a component is to use a strong function signature. This technique uses a standard method structure in a class module to define the parameters 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 signature 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 signature. In the same way that we want to standardize the format of the data leaving the component, 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 CHAPTER 6

155

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 component. 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 function 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 flexibility 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.

156

Data Services 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 drawbacks 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 CHAPTER 6

157

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 enumeration 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 modify this code.

158

Data Services 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 property 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 information based on a title and author search criteria. Double-click this file to start the application. 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 CHAPTER 6

159

is superior to a Variant array; however, using an XML transport will still eliminate the type checking of strong function signatures. The following code shows how an XML function signature would appear:
Public Function GetBooks _ (ByVal strArgs As String) As Recordset

6
COM+ DATA COMPONENTS

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 payload. 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 component. Clients wanting to send search criteria into a data component don’t have a simple way to package 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 create 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

160

Data Services PART II

After the recordset is created, you can use the standard methods discussed in Chapter 5 to create 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 modify 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 property 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 CHAPTER 6

161

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 an XML stream and then passes them to the data component. The resulting ADO recordset is then bound to a DHTML table for display.

6
COM+ DATA COMPONENTS

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 standardized 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 values; 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 information 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 flowchart 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

162

Data Services 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

Errors?

Yes

Append Error 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 CHAPTER 6

163

You can use this technique to append as many additional elements to the XML stream as you need. You might, for example, want to append a time stamp to the data. You might also want to 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 expects a certain format to properly convert the XML to a Recordset. Therefore, the client receiving 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

6
COM+ DATA COMPONENTS

When error handling is entered into the mix, we begin to see the power of a data services strategy relying on XML. We have built the case for a standard data component that accepts arguments 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 distributed 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 provides 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 understood 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.

164

Data Services 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 objectoriented 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 components. 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 project 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 CHAPTER 6

165

Creating Standards
Defining standard function signatures in Visual Basic is accomplished by creating abstract 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

6
COM+ DATA COMPONENTS

If we want to use this signature as a standard, it should be placed in a class module in a separate 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 function 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 accomplished 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 compiler acts as the standards enforcer for the project. It simply won’t allow the new class to compile 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.

166

Data Services 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 procedures 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 following 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 interface, 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 considerably easier than it would be if each developer defined his own custom method calls for encapsulating stored procedures.

COM+ Data Components CHAPTER 6

167

Key Principle
Use interfaces to define the communications points between components in an COM+ application.

6
COM+ DATA COMPONENTS

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 interfaces 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 application 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 system. Although we can enhance our payload objects to perform many related services, the fundamental 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+

168

Data Services 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 components always load into the memory space of the calling client, so performance will be excellent. 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 Search Parameters

Data Component Component Interface Execute Stored Procedure 3. The process is repeated to send the results of the stored procedure back to the calling client.

2. Search parameters are 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 experimentation only. Although the component has performed well under load, it isn’t intended to be used on production applications without further testing and modification. See Chapter 14, “Debugging and Deploying COM+ Applications,” for a complete discussion of performance testing.

COM+ Data Components CHAPTER 6

169

Overview
My DNA Payload consists of two class modules forming a simple object model. The top-level object in the model is the Dataset object, which is responsible for performing the data transformation operations. It also contains a collection of Field objects that can be used to pass arguments into components. Figure 6.10 shows the object model.
Dataset Fields Field

6
COM+ DATA COMPONENTS

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 Property
ADORecordset Count ErrDescription ErrNumber HTML Stream XML XSL

Dataset Properties

Description The data in Recordset form The number of Field objects in the collection A description of a system defined error A system defined error number The data in HTML form The data, schema, and error in XML form The data in XML form 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.

170

Data Services PART II

TABLE 6.2 Method
Add

Dataset Methods

Description Adds a Field object to the Fields collection Creates a recordset from the Fields collection Creates an XML stream with data, schema, and system information Loads XML from a file Loads XSL from a file Parses an XML stream containing data, schema, and system information Converts a recordset into a collection of Field objects Converts a Recordset into XML Removes a Field object from the collection Transforms XML into HTML using the XSL style sheet Converts XML into a Recordset

Collection2Recordset CreateStream LoadXML LoadXSL ParseStream Recordset2Collection Recordset2XML Remove XML2HTML XML2Recordset

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 properties of the Field object. TABLE 6.3 Property
FieldName FieldSize FieldType FieldValue

Field Object Properties

Description A String name for the Field object The size of the field as a Long Integer The field type as an ADO DataTypeEnum 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 CHAPTER 6

171

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

6
COM+ DATA COMPONENTS

Create a DNA Payload object

Data Component creates a new DNA Payload object

Add Parameters to the Fields Collection

Load XML into DNA Payload object

Create XML from Fields Collection

Create Collection of Fields from XML

Send XML Stream to Data component

Run query using Field objects as parameters 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 following code shows how parameters might be added to the Fields collection:
Dim objParams Set objParams objParams.Add objParams.Add As DNAPayload.Dataset = New DNAPayload.Dataset “Author”, adVarChar, “Hillier”, 50 “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 collection. The code in Listing 6.1 shows how the DNA Payload converts the Fields collection to a standalone Recordset:

172

Data Services 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 CHAPTER 6
objXMLStream.createElement(“ErrorNumber”) objXMLElement.Text = m_ErrNumber objXMLStream.firstChild.appendChild objXMLElement ‘Append Error Description Set objXMLElement = objXMLStream.createElement(“ErrorDescription”) objXMLElement.Text = m_ErrDescription objXMLStream.firstChild.appendChild objXMLElement ‘Save Document Text m_Stream = objXMLStream.XML

173

6
COM+ DATA COMPONENTS

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 creating 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 creates a new DNA Payload object

Data Component creates a new DNA Payload object

Stream property is loaded from passed in String Stream is parsed to populate Fields collection and error information Run query using Field objects as parameters for stored procedure

ADO Recordset and error information are added to DNA Payload

Outbound Stream is created

Stream property is returned to calling client

End

FIGURE 6.12
The data component uses the DNA Payload to return records.

174

Data Services 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 procedure. 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 CHAPTER 6

175

After the XSL and XML properties are set, the XML2HTML method can be used to create an HTML representation of the data. After the method is called, the resulting HTML is immediately 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)

6
COM+ DATA COMPONENTS

Conclusion
Although developers can use many different architectures to create Windows DNA applications, 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 payload object to have.

176

Data Services 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 allow you to exercise the payload object.
End

directory. This project will

COM+ Data Components CHAPTER 6

177

Step 8 Run the front-end project. 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.

6
COM+ DATA COMPONENTS

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 statement 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.

178

Data Services 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 CHAPTER 6

179

6
COM+ DATA COMPONENTS

FIGURE 6.16
XSL is used to transform the XML to HTML.

COM+ Transactions

CHAPTER

7
182

IN THIS CHAPTER
• Understanding Transaction Attributes • The Microsoft Distributed Transaction Coordinator 183 • Transactional Components • Monitoring Transactions 184 198

182

Data Services 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 negative impact on the overall system. The third attribute of transactions is isolation, which requires each transaction to operate independently 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 current transaction. Furthermore, other transactions can’t see the intermediate results of an executing 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 failure must not affect the transaction’s results.

COM+ Transactions CHAPTER 7

183

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 attributes 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 conform to the ACID requirements are said to engage in a two-phase commit. Two-phase commit engages in communication between transaction and resource managers to ensure compliance with the ACID principles. In COM+ applications, a two-phase commit is implemented by the Microsoft Distributed Transaction Coordinator (MSDTC).

7
COM+ TRANSACTIONS

The Microsoft Distributed Transaction Coordinator
MSDTC runs as a service under Windows 2000. MSDTC is responsible for initiating, monitoring, 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 twophase 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.

184

Data Services 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 components. 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 application; 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 attributes 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 CHAPTER 7

185

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 doesn’t support a setting of “disabled,” you won’t find this value available in Visual Basic. If you want transactions disabled for the component, set the property explicitly in COM+.

7
COM+ TRANSACTIONS

When a component is designated to be inside a transaction, COM+ uses the MSDTC to coordinate 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 components 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 attributes, but also other key object information such as the CLSID and the threading model supported 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 transaction 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

186

Data Services 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 relatively 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 transactional 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 transactional 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 CHAPTER 7

187

Transactional Boundary

A single method is invoked for all data access

Data Component

Database Single data component performs all write operations to the database

7
COM+ TRANSACTIONS

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 partitioning 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 separate 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 transaction. Therefore, the coarse data component can at times be performing a single operation,

188

Data Services 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 declarative 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 Shipping Address

Books 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 CHAPTER 7

189

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 procedures 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 simply write the data as instructed by the business services layer. In our designs, we typically create a business component for each business process in the application. In this system, we might create a business component to manage orders. The business 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 component 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 transaction initiated by the business component. Figure 7.6 shows a conceptual drawing of this architecture.
Transactional Boundary Data Component
Books

7
COM+ TRANSACTIONS

Book Title Credit Card Shipping Address

Business Component

Data Component Data Component

Payments Addresses

Transactional 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:

190

Data Services 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 participate 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 finegrained data components with transactional attributes set to Required.

Voting in Transactions
Components that have their transactional attributes set to provide transactional support participate 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 controlling 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 CHAPTER 7

191

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 database

7
COM+ TRANSACTIONS

Success? Yes

Vote for Transaction commit

Second data component called to write credit card information to database

No

Success? No Yes MSDTC Rolls Back Transaction

Vote for Transaction commit No No MSDTC Commits Transaction

End

Third data component called to write address information to database

Yes Success? Yes Success?

Vote for Transaction commit

Business component completes processing

FIGURE 7.7
Each component votes in a COM+ transaction.

192

Data Services 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 component, 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 completion 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 CHAPTER 7

193

7
COM+ TRANSACTIONS

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 transaction. In this project, the Manager class is used to transfer money between accounts. It

194

Data Services PART II

initiates and manages a transaction and calls the Reader and Writer as necessary to control 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 CHAPTER 7

195

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, we have to be careful with unhandled errors. Although it’s true that unhandled errors will cause 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. COM+ TRANSACTIONS

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 prevent 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.

196

Data Services 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 CHAPTER 7

197

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

7
COM+ TRANSACTIONS

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 articles and MSDN help to believe that support for SetAbort and SetComplete is only for backward 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 consistency 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.

198

Data Services 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 Method
SetComplete SetAbort

Values for Done and Consistency Bits

Done Bit
True True

Consistency Bit
True False

Key Principle
If you design for automatic transactions, don’t place error handlers in your components. 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 context 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 CHAPTER 7

199

7
COM+ TRANSACTIONS

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.

200

Data Services 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 CHAPTER 7

201

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 the balance of any account. Add the code in Listing 7.2 to the method. 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

7
COM+ TRANSACTIONS

202

Data Services 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 CHAPTER 7
‘Return Values vReturn = Array(curDebit, curCredit) Transfer = vReturn ‘Tell COM+ we succeeded objContext.SetComplete TransferExit: Exit Function TransferErr: ‘Tell COM+ we failed objContext.SetAbort ‘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

203

7
COM+ TRANSACTIONS

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 exercises, 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.

204

Data Services PART II

LISTING 7.4
Dim Dim Dim Dim

The OnClick Event

vReturn strDebit strCredit 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.

Business Services

III
231 255

PART

IN THIS PART
8 COM+ Security 207 9 COM+ Business Features

10 Asychronous COM+ Applications

COM+ Security

CHAPTER

8
208 210 213

IN THIS CHAPTER
• Distributed Security • Active Directory

• Active Directory Services Interface • COM+ Security Features • Conclusion 226 222

208

Business Services PART III

Security breaches in distributed systems certainly make for great headlines. From denial-ofservice 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 security. 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 transcend 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 passwords 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 CHAPTER 8

209

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 available 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 Public Key Username Password Client 1101101011011 Network 1101101011011 0000011011101 0000011011101 Client Signature Signature Client Private Key Client Public Key Client Signature Signature Server Private Key Username Password Server

8
COM+ SECURITY

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 snapin 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 legitimate. 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 connections. 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

210

Business Services 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 protocol 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 CHAPTER 8

211

COM+ applications gives you a standard way to implement security and personalization features 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) system, 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 application user, this often means having to remember multiple passwords. Single sign-on is a concept 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 custom security database with their own usernames, passwords, groups, and permissions. This database was independent of the SAM and therefore required a separate login by the client 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 determine 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.

8
COM+ SECURITY

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.

212

Business Services 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 CHAPTER 8

213

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 security 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.

214

Business Services 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 number 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 communicate 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 CHAPTER 8

215

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.

216

Business Services PART III

Within any DC, you can also find organizations (O) and organizational units (OU). These divisions 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 Attribute (domain component) O (organization) OU (organization unit) CN (common name)
DC

LDAP Path Attributes

Definition A registered domain name A company enterprise spanning a wide area network A division within a company enterprise 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 probably 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 CHAPTER 8

217

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:
MsgBox objADSI.Name & “ is class “ & objADSI.Class

8
COM+ SECURITY

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 someone 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 complete 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

218

Business Services 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 CHAPTER 8

219

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 here that GetEx() will also work for single-valued properties and will return an array with one 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

8
COM+ SECURITY

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 optimized 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 properties 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 multivalued 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.

220

Business Services 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 ecommerce 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 password. 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 CHAPTER 8

221

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 creating 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 compiled 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 mailing address information in the page. Figure 8.10 shows the results of the call for a given user.

NOTE
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.

8
COM+ SECURITY

FIGURE 8.10
Use this page to login to Active Directory.

222

Business Services 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 permissions. 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 component, 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 CHAPTER 8

223

FIGURE 8.12
Windows 2000 users are assigned to roles within a package.

8
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.

224

Business Services 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 programmatic security. The first is the IsSecurityEnabled method. This method tells you whether security is enabled at the application level. Remember, enabling security at the application 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 functionality. 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 CHAPTER 8

225

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.

8
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.

226

Business Services 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 ultimately making the request. You might, for example, want to log this information in the database 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 centralizes 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 managing 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 handle 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 information 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 CHAPTER 8

227

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

8-1.

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. 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

8
COM+ SECURITY

‘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, “\”))

228

Business Services 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 following 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 following 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 CHAPTER 8

229

FIGURE 8.16
Create roles for the components.

8
COM+ SECURITY

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.

230

Business Services 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 database. 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 • COM+ Constructors 238 232

• Compensating Resource Manager System 242

232

Business Services 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 activation 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 permeate 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 overall event capabilities, it was still a tightly bound system. To receive the events, an object variable 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 coupled 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 CHAPTER 9

233

COM+ Event System Publisher Event Class

Subscriber

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 defining 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:
Public Sub Process( _ ByVal strProductID As String, _ ByVal strDescription As String, _ ByVal strEMail As String, _ ByVal strTracking As String) End Sub

9
COM+ BUSINESS FEATURES

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.

234

Business Services 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 CHAPTER 9

235

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 information about all events that your component will receive. To create a new subscription, select the folder and choose New and then Subscription from the Action menu to start the New 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 specifically which one to associate with the subscription. Figure 9.4 shows how to select the event class in the wizard.

9
COM+ BUSINESS FEATURES

236

Business Services 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 CHAPTER 9

237

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. However, COM+ uses this mechanism to decouple the Publisher and Subscriber. When the Publisher calls the Process method, an event is broadcast throughout the COM+ event system. 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 combination of subscriptions by using the subscription’s property sheet.

9
COM+ BUSINESS FEATURES

238

Business Services 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 parameter 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 CHAPTER 9

239

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 Construct. COM+ calls this method each time your object is activated. The method passes in a reference to an IObjectConstructString object that you can use to access the construction 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

9
COM+ BUSINESS FEATURES

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

240

Business Services PART III

construct string is passed in when the object is activated, thus preserving the module-level variable 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 appropriate 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 CHAPTER 9

241

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.

9
COM+ BUSINESS FEATURES

FIGURE 9.9
All titles are returned and displayed in a table.

242

Business Services 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 mechanism. 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 perform 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 CHAPTER 9
3. The Data Component performs actions on the non-transactional resource and records Non-Transactional Resource all the actions in the durable log.

243

Business Component

CRM Worker (Data Component)

1. The Business Component begins a new transaction. 2. The Data Component creates a CRMClerk object to access the durable log.

CRMClerk object

CRM Worker (Data Component)

Log

4. After all components finish their work and vote in the transaction, the CRM is 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 durable log. CRMClerk should be declared as a local variable within the method of the CRM 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

9
COM+ BUSINESS FEATURES

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

244

Business Services 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 component 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 Value 1 2 4 7 16
CRM Flags

Meaning Receive Prepare phase messages Receive Commit phase messages Receive Abort phase messages Receive all messages 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 system 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 CHAPTER 9

245

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 implement 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 Method
SetLogControlVariants BeginPrepareVariants PrepareRecordVariants EndPrepareVariants BeginCommitVariants CommitRecordVariants EndCommitVariants BeginAbortVariants AbortRecordVariants EndAbortVariants ICrmCompensatorVariants Methods

Description Gives CRM access to the durable log to write new records if required Marks the beginning of the Prepare phase Called to prepare each log record Marks the end of the Prepare phase Marks the beginning of the Commit phase Called for each log record to commit Marks the end of the Commit phase Marks the beginning of the Abort phase Called for each log record to abort Marks the end of the Abort phase

9
COM+ BUSINESS FEATURES

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

246

Business Services 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 perform 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 CHAPTER 9

247

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 projects: • • •
Crmbiz.vbp

is the business layer. It contains a single class named Transactor.

Crmdata.vbp Worker.

is the data layer. It contains the CRM Worker as a class named It also contains a class to read data named Reader. is the Compensating Resource Manager.

Crmxml.vbp

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 transaction started by the business layer. 6. Open the code module for the Worker class. You will find a single method named AdjustBalance. This example is similar to the simulated bank transfer example in 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

9
COM+ BUSINESS FEATURES

‘Create a new CRMClerk Dim objClerk As COMSVCSLib.CRMClerk Set objClerk = New COMSVCSLib.CRMClerk ‘Register our CRMCompensator objClerk.RegisterCompensator “CRMXML.Compensator”, “Test Compensator”, 7

248

Business Services 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 transaction. 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 CHAPTER 9

249

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. Attempting to register a CRM that’s in recovery will result in a Recovery in Progress error. If this error is received, the CRM Worker should wait and attempt registration again before proceeding.

9
COM+ BUSINESS FEATURES

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 operation is performed.

250

Business Services 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 CHAPTER 9

251

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 subscriber.dll and publisher.dll into the COM+ application. Step 9 Locate the Subscriber component under the Components folder of the new COM+ application. 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.

9
COM+ BUSINESS FEATURES

FIGURE 9.12
Add a new subscription to receive system errors.

252

Business Services 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 directory 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 CHAPTER 9

253

FIGURE 9.13
Search for records using the Web pages.

9
COM+ BUSINESS FEATURES

Asynchronous COM+ Applications

CHAPTER

10
256

IN THIS CHAPTER
• The Microsoft Message Queue • MSMQ Applications • Queued Components 258 265

256

Business Services PART III

Throughout the book so far, we’ve designed and implemented components that worked synchronously 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 immediately 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 asynchronously 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 consist of either text or binary information. Messages can be delivered to a queue by one distributed 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 messages within a local area network (LAN).

Asynchronous COM+ Applications CHAPTER 10

257

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 computers 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 indicate 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 COM+ APPLICATIONS

258

Business Services 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 CHAPTER 10

259

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. is the time when the queue was first created. is the time when the queue properties were last changed.

CreateTime ModifyTime

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. is the relationship parameter for CreateTime. is the relationship parameter for ModifyTime.

RelCreateTime RelModifyTime

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 ‘The following is the ServiceTypeGUID we ‘want to search for Const msmqServiceTypeGUID$ = “{581EA041-8D8E-11d1-B101-000629142E7B}”

10
ASYNCHRONOUS COM+ APPLICATIONS

260

Business Services 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 collection 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 CHAPTER 10

261

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 simultaneously. 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. fires when a queue has an error delivering a message.

ArrivedError

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 application, you must explicitly call the EnableNotification method again to receive the next event.

10
ASYNCHRONOUS COM+ APPLICATIONS

NOTE
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.

262

Business Services PART III

The following code shows how the recipient of a message connects to a queue for asynchronous 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 CHAPTER 10

263

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 example. 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. 6. Compile the project into an ActiveX DLL. You won’t place your components in a COM+ application because they won’t work correctly in the stateless environment of 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.

10
ASYNCHRONOUS COM+ APPLICATIONS

264

Business Services 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 programming. 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 CHAPTER 10

265

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 Component

Server Component Method call Security context

Method call

Security context

QC Player

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. The QC Recorder delivers the message to a transacted MSMQ queue, meaning that the message is accepted only if any client-side transactions commit. If the QC system is part of an 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.

10
ASYNCHRONOUS COM+ APPLICATIONS

266

Business Services 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 CHAPTER 10

267

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 COM+ APPLICATIONS FIGURE 10.6
Several private queues are built for an application.

268

Business Services 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+ application. 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 synchronously 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 CHAPTER 10

269

programmers. A moniker is simply a formal name. In the QC system, this formal naming dictates 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 parameters 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 identify it in the queue:
Set objServer= GetObject(“queue:Priority=7,Label=’Test’/new:MyQC.Server”)

TABLE 10.1 Parameter

Queue Moniker Parameters

Description Specifies the computer where the queue can be found Specifies the queue to receive the message Computer and queue formatted as ComputerName/QueueName The MSMQ format An unsigned Integer value The message authentication level: 0=none, 1=always Specifies the delivery option: 0=express, 1=recoverable Specifies the encryption algorithm Specifies the hash function Specifies a journal option: 0=none, 1=dead letter, 2=journal A label for the message

ComputerName QueueName PathName FormatName AppSpecific AuthLevel Delivery EncryptAlgorithm HashAlgorithm Journal Label

10
ASYNCHRONOUS COM+ APPLICATIONS

270

Business Services PART III

TABLE 10.1 Parameter

Continued

Description Specifies maximum time in seconds Specifies maximum time in seconds for message to be received Message priority, 0-7 Specifies privacy level Specifies trace options

MaxTimeToReachQueue MaxTimeToReceive Priority PrivLevel Trace

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 arguments 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 synchronous 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 CHAPTER 10

271

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 accomplish this task, simply mark the QC to support transactions. Figure 10.8 shows a conceptual drawing of this process.

Business Component Requires New

Send E-Mail Command

Queued Component Supported

E-Mail Message

Database Write

SQL Server

10
ASYNCHRONOUS COM+ APPLICATIONS

FIGURE 10.8
The queued method call will be rolled back along with a failed database transaction.

272

Business Services 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 component 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 message 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 Card Queued Component Supported Product

Order Data

Order Data Business Component Requires New

Supported

Supported

Queue

Order Data

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 CHAPTER 10

273

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 exception 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 asynchronous, 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\Exercise 10-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 10-1. Copy the contents from the CD-ROM directory into this new directory.

10
ASYNCHRONOUS COM+ APPLICATIONS

274

Business Services 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 component into an ActiveX DLL.

Asynchronous COM+ Applications CHAPTER 10

275

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 transaction 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. Step 12 Open the code window for the class named GUID. This class generates unique order numbers for the system. I find that having a component that can generate unique identifiers is useful in many systems.

10
ASYNCHRONOUS COM+ APPLICATIONS

276

Business Services 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 construction. 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 construction. 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 CHAPTER 10

277

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 COM+ APPLICATIONS

FIGURE 10.12
Use the form to place an order.

278

Business Services 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.

User Services

IV
281 311 331

PART

IN THIS PART
11 COM+ and the Internet 12 COM+ and Win32

13 Integrating COM+ with Groupware 14 Debugging and Deploying COM+ Applications 353 15 COM+ Catalog Administration 377

COM+ and the Internet

CHAPTER

11
290

IN THIS CHAPTER
• New Internet Information Server Features 282 • Creating Transactional Web Pages • Accessing ASP Objects with COM+ Components 298 • Understanding XSL Style Sheets 300

282

User Services 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 integration 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 CHAPTER 11

283

applications like CGI. Soon, however, problems began to emerge with this design. Improperly designed applications that crashed while in the same process as the Web server caused the entire server to fail. 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 information. 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 directory 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.

11
COM+ AND THE INTERNET

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 available. 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.

284

User Services 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 application for maintenance. This is particularly important when you want to make changes to a component 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 associated with the process. Figure 11.5 shows the COM+ package for pooled applications in the Component Services explorer.

COM+ and the Internet CHAPTER 11

285

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.

286

User Services 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 associated 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 associated 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 Property
Number Description ASPCode ASPDescription Source ASPError Properties

Name The standard COM error number The standard COM error description The ASP processing error number The ASP processing error description The actual source code that caused the error

COM+ and the Internet CHAPTER 11

287

Property
Category File Line Column

Name Indicates if ASP, script, or a COM object caused the error Name of the ASP file where the error occurred Line number where the error occurred Column number where the error occurred

11
COM+ AND THE INTERNET

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

288

User Services 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 application directory. Create this new application directory by right-clicking the project directory 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 CHAPTER 11

289

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.

290

User Services 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 perform some initial checks on a page with an .asp extension to see if it actually contains serverside 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 performing 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 application. The @TRANSACTION directive is always placed as the first line in any ASP page; otherwise, an error is generated. When you use the directive, the operations performed in any page

COM+ and the Internet CHAPTER 11

291

are treated as a unit and function in much the same way as work performed by a conventional COM+ component. The @TRANSACTION directive has the following values: • • • •
@TRANSACTION=REQUIRES_NEW—The ASP

11
COM+ AND THE INTERNET

page will always initiate a new transaction. 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

292

User Services PART IV

code both OnTransactionCommit and OnTransactionAbort event handlers that are automatically 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
Language=”VBSCRIPT” %>

<%@Transaction=”REQUIRES_NEW” <%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 transactions 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 important 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 CHAPTER 11

293

The Transfer method transfers processing to a new ASP page in a manner similar to the Redirect method. The difference is that a Redirect actually requires a round trip to the client before control is transferred. With the Transfer method, all variables and submitted data are 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 designated as REQUIRES_NEW, and subsequent pages called by Transfer or Execute can be designated 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

11
COM+ AND THE INTERNET

<%@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 %>

294

User Services 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 subsequent 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 generally return to the original page. This means that the second page can have increased responsibility 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 attractive. 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 CHAPTER 11

295

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 keyword. 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
Class Customer Private m_Name Public Property Let Name(strName) m_Name = strName

Creating a Simple Property

296

User Services 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 CHAPTER 11
Response.Write “<H1>” & objCustomer.Name & “</H1>” Response.Write “<H1>” & objCustomer.Purchase & “</H1>” %> </BODY> </HTML>

297

11
COM+ AND THE INTERNET

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 necessary 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 custom 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.

298

User Services 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+ component 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
strHTML strHTML strHTML strHTML = = = =

Creating an HTML Table

“” strHTML & “<TABLE><TR><TH>Name</TH>” strHTML & “<TD><INPUT></TD></TR><TR>” strHTML & “<TH>Address</TH><TD><INPUT>”

COM+ and the Internet CHAPTER 11
strHTML strHTML strHTML strHTML strHTML = = = = = strHTML strHTML strHTML strHTML strHTML & & & & & “</TD></TR><TR><TH>City</TH>” “<TD><INPUT></TD></TR><TR>” “<TH>State</TH><TD><INPUT>” “</TD></TR><TR><TH>Zip</TH>” “<TD><INPUT></TD></TR>”

299

11
COM+ AND THE INTERNET

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

300

User Services 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 implementations 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 transform 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 CHAPTER 11

301

LISTING 11.8

A Simple XML File

11
COM+ AND THE INTERNET

<?xml version=”1.0”?> <?xml:stylesheet type=”text/xsl” href=”memo.xsl”?> <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 closing 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

302

User Services 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 identifying 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 CHAPTER 11

303

XSL allows you to select information from the tag or attributes associated with the tag. For example, our <PAGE> tag has an attribute, Number, associated with it. To select data from an attribute, use the @ designator. The following code shows how to select the page number attribute:
<xsl:value-of select=”MEMO/PAGE/@Number”/>

11
COM+ AND THE INTERNET

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 repeated 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>

304

User Services 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 CHAPTER 11

305

XSL Elements
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 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/>

11
COM+ AND THE INTERNET

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 determine 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;”>

306

User Services 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 separate database for the shopping cart information. Start the SQL Server Enterprise Manager and create a new database named Carts.

COM+ and the Internet CHAPTER 11

307

Step 4 From the SQL Enterprise Manager, start the SQL Query Analyzer. Connect to the Carts database and open the file carts.sql. This is the SQL script to create the tables and stored procedures for the exercise. Run the script on the Carts database.

11
COM+ AND THE INTERNET

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 parameters 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.

308

User Services 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 formatted 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 templates are used to create a form for each returned title. You can add books to the cart by submitting 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 CHAPTER 11

309

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
312 319

IN THIS CHAPTER
• Maintaining Application State • User Interface Strategies

312

User Services 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 available 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 CHAPTER 12

313

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 shows how a payload is used to create a collection.

12
COM+ AND WIN32

Data Data Data Data Data Data Data

Data Data Data Data Data Data Data

Data Data Data Data Data Data Data

Object Object Object Object Object Object Object Payload To Business Service Layer

GUI User Services Layer

Collection State/Workflow Layer

Transport

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 necessary. 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.

314

User Services 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 partition 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 polymorphism 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 CHAPTER 12
End Property Public Property Get NewEnum() As IUnknown ‘Supports For...Each End Property

315

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. The ICollection interface describes the structure of a collection and is responsible for containing the items within it. However, you can’t predict at the outset what objects you want in 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

12
COM+ AND WIN32

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.

316

User Services 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 disconnected 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 CHAPTER 12

317

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 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.2 shows the completed project.

12
COM+ AND WIN32

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 properties 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.

318

User Services 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 disconnected 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 property, 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 CHAPTER 12

319

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 investigate 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.

320

User Services 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 interest. 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 discussed 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 CHAPTER 12

321

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

322

User Services PART IV

have no real way to know what events are supplied by the control. You can overcome this limitation 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 application 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 CHAPTER 12

323

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 similar 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).

324

User Services 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 doubleclick fires a custom event called Navigate. When you see the results in the second control, 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 regarding its capabilities.

COM+ and Win32 CHAPTER 12

325

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, 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:
<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>

12
COM+ AND WIN32

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 Attribute
ApplicationName Border BorderStyle Caption CommandLine

HTA Attributes

Description The application’s name within the operating system. The type of window border with these possible values: thick (the default), dialog, none, and thin. The look of the window border with these possible values : normal (the default), complex, raised, static, and sunken. Determines if the window has a title bar. Possible values are yes (the default) and no. Returns command-line parameters used when the application was launched.

326

User Services PART IV

TABLE 12.1 Attribute
Icon

Continued

Description The application’s icon. Determines if the window has a maximize button. Possible values are yes (the default) and no. Determines if the window has a minimize button. Possible values are yes (the default) and no. Determines if the application appears in the taskbar. Possible values are yes (the default) and no. Determines if more than one copy of the file can run. Possible values are yes (the default) and no. Determines if the window has a system menu. Possible values are yes (the default) and no. The application’s version number. Sets the size of the window. Possible values are normal (the default), minimize, and maximize.

MaximizeButton MinimizeButton ShowInTaskBar SingleInstance SysMenu Version WindowState

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 functions 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 CHAPTER 12

327

12
FIGURE 12.8
HTA files can be run directly from the server.

COM+ AND 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 12\Exercise 12-1. This directory contains a partially complete project.

Templates\Chapter

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.

328

User Services 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 CHAPTER 12

329

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 In the Project Explorer, locate the project named BusinessStub. This is the COM+ component. In this project, locate and open the AuthorStub class that contains two simple methods for 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 database, 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.

12
COM+ AND WIN32

NOTE
The connection string defined in this class might have to be modified for your configuration.

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 recordset for update.

330

User Services 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 Groupware

CHAPTER

13

IN THIS CHAPTER
• Integrating Exchange 2000 Server with COM+ 332 • Integrating Microsoft Outlook 2000 with COM+ 338 • Integrating Digital Dashboards with COM+ 348

332

User Services 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 communicate 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 information 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 information store. In this database, you will find email messages, contacts, and scheduling information. 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 afterthought. 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 CHAPTER 13

333

FIGURE 13.1
Web storage is structured similar to a file system.

13
INTEGRATING COM+ WITH GROUPWARE

FIGURE 13.2
Web storage is accessible across the Internet.

334

User Services 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 provides 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 connection 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 CHAPTER 13

335

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 containment 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 namespaces 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 Set objConnection = New ADODB.Connection Set objRecordset = New ADODB.Recordset strConnect = “file://./backofficestorage/dc.local/MBX/SCOTH/Contacts” objConnection.Provider = “ExOLEDB.DataSource.1” objConnection.Open strConnect strSQL strSQL strSQL strSQL strSQL = = = = = “select “ strSQL & Chr$(34) & “DAV:displayname” & Chr$(34) strSQL & “ from scope (‘shallow traversal of “ strSQL & Chr$(34) & strConnect & Chr$(34) & “‘) “ strSQL & “ORDER BY “ & Chr$(34) & “DAV:displayname” & Chr$(34)

13
INTEGRATING COM+ WITH GROUPWARE

objRecordset.Open strSQL,objConnection objRecordset.MoveFirst Do While Not objRecordset.EOF MsgBox objRecordset.Fields(“DAV:displayname”).Value objRecordset.MoveNext Loop

336

User Services 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 CHAPTER 13
With objMessage .To = “SCOTH” .From = “JOHNQ” .Subject = “CDO is easy” .TextBody = “Here is a new message.” .Send End With

337

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. 3. Open the project group named cdoxml.vbg. This project contains a single class that will 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 displayed. 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.

13
INTEGRATING COM+ WITH GROUPWARE

338

User Services 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, including 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 CHAPTER 13

339

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
INTEGRATING COM+ WITH GROUPWARE

Forms can be customized in Outlook only when the form is visible. You can customize any visible 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.

340

User Services 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 manipulate form interfaces, create and send email, assign tasks, and interact with COM+ components.

Integrating COM+ with Groupware CHAPTER 13

341

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 wanting 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 available 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
INTEGRATING COM+ WITH GROUPWARE

The Item Object
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 Event
Open Read Write

Item Events

Description Fires when an item is opened Fires when an item is opened for editing Fires when changes to an item are saved

342

User Services PART IV

TABLE 13.1 Event
Close Send Reply ReplyAll Forward

Continued

Description Fires when an item is closed Fires when an item is sent Fires when a user replies to this item Fires when a user replies to all recipients of this item Fires when this item is forwarded Fires when a property of the item is changed Fires when a user-defined property is changed Fires when a user-defined action is executed

PropertyChange CustomPropertyChange CustomAction

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 current 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 CHAPTER 13

343

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 environment 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 communication 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 model externally from Visual Basic, you can use the named constants found in the Outlook object model. Table 13.2 lists the named constants for creating items and their associated enumerated values. Although you can create a new item of any type supported by Outlook, this chapter focuses on several key items, including the MailItem, TaskItem, and ContactItem objects. TABLE 13.2 Constant
olMailItem olAppointmentItem olContactItem olTaskItem olJournalItem olNoteItem olPostItem

13
INTEGRATING COM+ WITH GROUPWARE

Create Item Constants

Value
0 1 2 3 4 5 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

344

User Services 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 Constant

Constants for the GetDefaultFolder Method

Value
3 4 5 6 9 10 11 12 13

olFolderDeletedItems olFolderOutbox olFolderSentMail olFolderInbox olFolderCalendar olFolderContacts olFolderJournal olFolderNotes olFolderTasks

In addition to default folders, you can locate any folder in the list through the Folders collection. 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 CHAPTER 13

345

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 publish it as MyTask, the message class for the custom form will be IPM.Task.MyTask.

13
INTEGRATING COM+ WITH GROUPWARE

The ContactItem Object
The ContactItem object represents a new contact in Outlook. Contacts normally represent personal 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 folders in much the same way as tasks. Once a contact is added to a folder, you can set key information, 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.

346

User Services 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 appropriate 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 several 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 CHAPTER 13

347

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
INTEGRATING COM+ WITH GROUPWARE 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 recipient opens the form. Switch the form to the read view by clicking the Edit Read Page button. Figure 13.8 shows the read view of the form.

348

User Services 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 original 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 message 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, companies 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 CHAPTER 13

349

are simple to implement, but in practice, they can be powerful knowledge management solutions. Figure 13.9 shows an example of a digital dashboard running in Outlook 2000.

13
INTEGRATING COM+ WITH GROUPWARE 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.

350

User Services 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 certainly 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 corporate 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 CHAPTER 13

351

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 information you can include in a corporate portal. Step 4 In the Pubs class, modify the connection string to access the pubs database for your configuration. 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
INTEGRATING COM+ WITH GROUPWARE

Using the New Page
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.

352

User Services PART IV

FIGURE 13.11
A corporate portal can combine many types of information.

Debugging and Deploying COM+ Applications

CHAPTER

14

IN THIS CHAPTER
• Debugging COM+ Components • Deploying COM+ Applications • Analyzing COM+ Applications 354 356 363

354

User Services 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 application. 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 CHAPTER 14

355

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 nonconfigured 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 advantages 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 environment, 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 compilation, 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 #If COM+ Then objContext.SetComplete #End If

14
DEBUGGING AND DEPLOYING COM+ APPLICATIONS

Debugging in Visual InterDev
Debugging a COM+ application called from within Visual InterDev presents some special challenges. 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 credentials 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.

356

User Services 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 traditional application and requires some thought and planning to be successful.

Debugging and Deploying COM+ Applications CHAPTER 14

357

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 create 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 connection 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
Deploying the business services layer is all about deploying COM+ components. Although other layers—most notably data services—can contain COM+ components, the mechanics for 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 environment, you already have COM+ components installed and working. Deploying these components 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.

14
DEBUGGING AND DEPLOYING COM+ APPLICATIONS

358

User Services PART IV

Exporting an application is done by simply right-clicking the application of interest and selecting 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 CHAPTER 14

359

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 file in the directory you created earlier.
check.msi.

Place this

4. After the MSI file is exported, open the Windows File Explorer and examine the directory 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 initially 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 interface and an appropriate proxy for your COM+ application. Because the client and the COM+ component won’t reside on the same machine, you must do some extra work to set up.

14
DEBUGGING AND DEPLOYING COM+ 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 target 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 component can succeed.

360

User Services 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 environment. 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 creating 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 software. 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 CHAPTER 14

361

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 compatible 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 application, 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 correct 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.1 at the end of this chapter walks you through the process of creating a complete setup.

14
DEBUGGING AND DEPLOYING COM+ APPLICATIONS

Group Policies
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 designated 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

362

User Services PART IV

policies by right-clicking any domain, site, or organizational unit and selecting to view properties. 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 CHAPTER 14

363

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 distributed 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+ application. 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
DEBUGGING AND DEPLOYING COM+ 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

364

User Services 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 quantitatively 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 certainly 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 during 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 compute MRS. Figure 14.11 shows the dialog for selecting performance counters in WAS.

Debugging and Deploying COM+ Applications CHAPTER 14

365

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 following 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. The stress level is set by specifying the number of threads to run against the Web site. When specifying stress, begin with just one thread and work your way up slowly. For each run of 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 utilization remains low, a COM+ component is likely causing a system bottleneck.

14
DEBUGGING AND DEPLOYING COM+ APPLICATIONS

366

User Services 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 techniques or architectures; however, I often find that this justification lacks any quantitative backing. 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 mystical 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 language 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 execute a query and return the results. Records Returned 25 150 5000 MSR 20.8 130 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 25 150 5000 MSR 20.8 125 2500

Debugging and Deploying COM+ Applications CHAPTER 14

367

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 component was used to encapsulate data access, the resulting MSR was 13. This means that VB components 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 testing your application before deployment to ensure that it will perform well.

14
DEBUGGING AND DEPLOYING COM+ APPLICATIONS

Load Balancing
In a properly designed COM+ application, your system should never be bound by a component. 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.

368

User Services 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 serverside 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 CHAPTER 14

369

FIGURE 14.13
Set properties for the cluster.

14
DEBUGGING AND DEPLOYING COM+ 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.

370

User Services 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, however, 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 CHAPTER 14

371

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
DEBUGGING AND DEPLOYING COM+ 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.

372

User Services 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 CHAPTER 14

373

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 rightclicking 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
DEBUGGING AND DEPLOYING COM+ 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).

374

User Services 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 CHAPTER 14

375

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
DEBUGGING AND DEPLOYING COM+ APPLICATIONS

COM+ Catalog Administration

CHAPTER

15

IN THIS CHAPTER
• The COM+ Administration Object Model 378 • Performing COM+ Administration with the Windows Scripting Host 383

378

User Services 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 running. 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 CHAPTER 15

379

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 Method
BackUpREGDB Connect ExportApplication GetCollection GetCollectionByQuery GetEventClassesForIID GetMultipleComponentsInfo ImportComponent InstallApplication InstallComponent InstallEventClass InstallMultipleComponents InstallMultipleEventClasses QueryApplicationFile RefreshComponents RestoreREGDB ServiceCheck ShutdownApplication COMAdminCatalog Methods

Description Backs up registration database Connects to a COM+ catalog Exports an application or application proxy Returns a collection of catalog information Gets a collection of catalog information based on item keys Gets a list of event classes that implement a given interface Returns information about all components found in a given DLL file Imports a registered component Installs an application or proxy MSI file Installs an unregistered component Installs a component as an event class Installs components from several files Installs components from several files as event classes Returns information about a COM+ application Refreshes component information from the Registry Restores registration database Checks the status of a COM+ service Shuts down a given application

15
COM+ CATALOG ADMINISTRATION

380

User Services 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 computers, 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 Argument
Applications Components ComputerList DCOMProtocols ErrorInfo InProcServers InterfacesForComponent LocalComputer MethodsForInterface PropertyInfo PublisherProperties RelatedCollectionInfo Roles RolesForComponent RolesForInterface RolesForMethod Root

Component Services Administration Collections

Collection Returned The collection of all COM+ applications The collection of all components for an application The collection of all machines managed by the explorer The collection of all protocols used by the DCOM system A collection of extended error information for operations on multiple objects The collection of all in-process servers on the system The collection of all interfaces for a given component The collection of settings for the local computer The collection of all methods for a given interface The collection of properties supported by a given collection The collection of properties for a publisher related to a given subscription A collection of information about other collections that are associated with the current collection A collection of roles for a given application A collection of roles assigned to a given component A collection of roles assigned to a given interface A collection of roles assigned to a given method The top-level collection

COM+ Catalog Administration CHAPTER 15

381

Argument
SubscriberProperties TransientSubscriptions UsersInRole

Collection Returned A collection of subscriber properties for a given subscription A collection of transient subscriptions, which don’t survive a system failure 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. 4. This project is designed to allow you to see some of the collections associated with 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.

15
COM+ CATALOG ADMINISTRATION

382

User Services 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 collections 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 applications, a COMAdminCatalogObject contains an individual application. Similarly, if you are examining 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 CHAPTER 15

383

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 interfaces 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, administrators 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 using Notepad. Saving a file from Notepad with a .vbs extension tells WSH that VBScript is 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.

15
COM+ CATALOG ADMINISTRATION

384

User Services 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 administration 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 create 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 Method
CreateObject(ProgID,KeyName) DisconnectObject VarName Echo Message GetObject(Path,ProgID,KeyName) Quit Code

Methods of the WScript Object

Description Creates an object instance based on a ProgID Disconnects an object that was connected for the purpose of receiving events Outputs information in a message box Gets an object instance that’s already created Ends the current script

Along with the WScript methods, several properties are also supported. Perhaps the most useful of the available properties is Arguments, which allows you to access command-line arguments that were passed in when the script was started. The Arguments property returns a

COM+ Catalog Administration CHAPTER 15

385

zero-based array of the arguments passed in to the script. Table 15.4 lists all the properties supported by the WScript object. TABLE 15.4 Property
Application Arguments FullName Name Path ScriptFullName ScriptName Version

Properties of the WScript Object

Description References the WSH application object A collection of arguments passed in to the script The full path to the scripting engine A friendly name for the scripting engine The path to the scripting engine Complete path to the running script Name of the running script 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 methods 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 Member
Environment SpecialFolders CreateShortcut ExpandEnvironmentStrings Popup RegDelete RegRead RegWrite Run

Members of the Shell Object

Description Returns environment information such as processor type and available memory Returns a reference to special folders such as the Desktop or Start menu Creates a shortcut to a file Returns environment variables Pops up a message box Deletes a Registry key or value Reads a Registry value Writes a Registry key or value Starts an executable program

15
COM+ CATALOG ADMINISTRATION

386

User Services 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 running 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 CHAPTER 15

387

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.

388

User Services PART IV

Step 4 Open the code window for frmWizard. In the [General][Declarations] section, notice several 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 button 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.

PubsOnLine.com

V
391 417

PART

IN THIS PART
16 Designing the PubsOnLine.com Application 17 Building the PubsOnLine.com Application

Designing the PubsOnLine.com Application

CHAPTER

16

IN THIS CHAPTER
• Problem Statement 392 392 393 403 • Gathering Requirements

• Identifying Actors and Use Cases

• Screen Shots and the Paper Prototype • Data Model 407 408 415

• System Models

• Defining Components

392

PubsOnLine.com 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 problem 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 development effort. In the end, the software must support the business objectives of the company; otherwise, 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 stakeholders. 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 expectation 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 feature 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 identified the following feature set.

Designing the PubsOnLine.com Application CHAPTER 16

393

Membership and Personalization
This feature is consistently rated among the most important features of the new site. It allows 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.

16
DESIGNING THE PUBSONLINE.COM APPLICATION

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 information. Personnel could more accurately analyze site traffic and adjust the Web site accordingly. 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 performing 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

394

PubsOnLine.com 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 Login Check Out View Cart Add Book to Cart Iteration #2 Analyze Customer Data Manage Promotions

Login

Analyze Customer Data

Check out Customer Manage Promotions View Cart Administrator

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 information 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 CHAPTER 16

395

• Primary Actor: Customer • Domain Expert(s): Scot Hillier, Patrick Babcock • Revision: 1.00 • Revised Date: 01/15/00

16
DESIGNING THE PUBSONLINE.COM APPLICATION

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

396

PubsOnLine.com PART V

[ No ]

Does user have a cookie? [ Yes ]

Enter Username and Password

[ No ] Are Username and Password Authentic? [ Yes ] New Cart Created

Is cookie valid? [ Yes ]

[ No ]

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 CHAPTER 16

397

Add Book to Cart
This use case documents the steps necessary to search, display book details, and then add the 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

16
DESIGNING THE PUBSONLINE.COM APPLICATION

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.

398

PubsOnLine.com PART V
Logged In Request a new search Select to add book to cart

Search form visible

Cart contents displayed [ Yes ] Does customer want to change quantities [ No ]

Request to search by Author, Title, or Publisher

Change quantities 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 CHAPTER 16

399

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 “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.

16
DESIGNING THE PUBSONLINE.COM APPLICATION

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

400

PubsOnLine.com 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 ] [ No ] Change quantities for book(s) in cart Change quantities?

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 CHAPTER 16

401

Checkout
This use case documents the steps necessary to enter the shipping address, review the book 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

16
DESIGNING THE PUBSONLINE.COM APPLICATION

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.”

402

PubsOnLine.com PART V
Logged In

Shipping address displayed

Enter new address

Does customer want to 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 CHAPTER 16

403

Screen Shots and the Paper Prototype
With the use cases completed, there is a complete text-based description of the system to be 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.

16
DESIGNING THE PUBSONLINE.COM APPLICATION

FIGURE 16.6
This screen shows the home page.

404

PubsOnLine.com 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 CHAPTER 16

405

16
DESIGNING THE PUBSONLINE.COM APPLICATION

FIGURE 16.9
This screen shows the search results page.

FIGURE 16.10
This screen shows the book details page.

406

PubsOnLine.com 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 CHAPTER 16

407

16
DESIGNING THE PUBSONLINE.COM 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 database. Figure 16.14 shows the database model for the first iteration of our application.

408

PubsOnLine.com 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 respective 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 CHAPTER 16

409

<<Active Server Page>> order.asp (from ASP) <<Class Module>> CCart (from Cart)

<<Class Module>> CCreateCart (from Cart)

<<Class Module>> CGetCartDetails (from Cart)

<<Class Module>> CUpdateCart (from Cart)

16
DESIGNING THE PUBSONLINE.COM APPLICATION

<<Active Server Page>> contents.asp (from ASP)

<<Class Module>> CPutOrder (from Cart)

<<Class Module>> CPutCartItem (from Cart)

<<Class Module>> CDeleteCartItem (from Cart)

<<Active Server Page>> home.asp (from ASP) <<Class Module>> CMembership (from Membership)

<<Class Module>> CPutADSIAAddress (from Membership) <<Class Module>> CPutADSIAddress (from Membership)

<<Active Server Page>> validate.asp (from ASP)

<<Active Server Page>> shipping.asp (from ASP)

<<Class Module>> CGetADSIFriendlyName (from Membership)

<<Active Server Page>> results.asp (from ASP) <<Class Module>> CBooks (from Books)

<<Class Module>> CGetBookDetails (from Books)

<<Class Module>> CGetTitlesByPublisher (from books) <<Class Module>> CGetTitlesByAuthor (from books)

<<Active Server Page>> details.asp (from ASP)

<<Class Module>> 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 package, 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

410

PubsOnLine.com 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 CHAPTER 16

411

write data to Active Directory. For the Log In use case, you might be authenticating using either an HTML form or a cookie. Therefore, you need two separate methods on the CMembership class to support the functionality. The initial call will always come from a Web page to CMembership where it will be processed and resulting HTML returned. Figure 16.17 shows the sequence diagram for an HTML form login.

16
DESIGNING THE PUBSONLINE.COM APPLICATION

: validate.asp : Customer

: CMembership

: CGetADSIFriendlyName

CCreateCart

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 welcomes 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.

412

PubsOnLine.com 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 CHAPTER 16

413

16
DESIGNING THE PUBSONLINE.COM APPLICATION
: results.asp : Customer CBooks : CGetTitlesByAuthor : CGetTitlesByPublisher : CGetTitlesByTitle

Search( ) Object : Customer

FIGURE 16.19
This is the sequence diagram for searching the database.

: details.asp : Customer

CBooks

: CGetBookDetails

: CPutCartItem

ShowDetails ( )

FIGURE 16.20
This is the sequence diagram for adding a book to the shopping cart.

414

PubsOnLine.com 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 : Customer

CCart

CUpdateCart

: 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 shipping 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 CHAPTER 16

415

submitted and processed from the same page. Figure 16.22 shows the sequence diagram for changing the shipping address.

16
DESIGNING THE PUBSONLINE.COM 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 operation, 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 packaging, 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.

416

PubsOnLine.com PART V

: order.asp : Customer

: CCart

: CPutOrder

Order ( )

FIGURE 16.23
This is the sequence diagram for completing the order.

<<ActiveX DLL>> NTSPayload

<<ActiveX DLL>> POLBixServ

<<ActiveX DLL>> POLCommon

<<ActiveX DLL>> POLinterfaces

<<ActiveX DLL>> POLDataServ

FIGURE 16.24
This is the component diagram for the system.

Building the PubsOnLine.com Application

CHAPTER

17

IN THIS CHAPTER
• Development Environment • Creating the Database 419 425 418

• Creating the COM+ Components • Creating the Web Interface 445

418

PubsOnLine.com PART V

Chapter 16 examined the design documents for the PubsOnLine e-commerce site. In this chapter, 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 necessary 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 installation 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 CHAPTER 17

419

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
BUILDING THE PUBSONLINE.COM 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 developers. These tables simply associate the title, author, and publisher information. A many-tomany 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.

420

PubsOnLine.com 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 database. Figure 17.5 shows the Query Analyzer with the PubsOnLine database selected.

Building the PubsOnLine.com Application CHAPTER 17

421

17
BUILDING THE PUBSONLINE.COM 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 create 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.

422

PubsOnLine.com 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 clicking 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 available 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 CHAPTER 17

423

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 password for this account as compassword. Set the default database to PubsOnLine.

17
BUILDING THE PUBSONLINE.COM 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.

424

PubsOnLine.com 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 CHAPTER 17

425

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
BUILDING THE PUBSONLINE.COM 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.

426

PubsOnLine.com 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 CHAPTER 17

427

17
BUILDING THE PUBSONLINE.COM 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.

428

PubsOnLine.com 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 interfaces: IReadData, IWriteData, and IWriteErrors. IReadData and IWriteData are implemented 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 writing 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 CHAPTER 17

429

17
BUILDING THE PUBSONLINE.COM 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

430

PubsOnLine.com PART V

LISTING 17.1
Dim Dim Dim Dim Dim Dim

Continued

objLog As POLInterfaces.IWriteErrors lngNumber As Long strDescription As String objInbound As DNAPayload.Dataset objOutbound As DNAPayload.Dataset 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 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 m_Connect = pCtorObj.ConstructString End Sub

431

17
BUILDING THE PUBSONLINE.COM APPLICATION

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 comment 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 project 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 transformation process.

432

PubsOnLine.com 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 CHAPTER 17

433

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
BUILDING THE PUBSONLINE.COM APPLICATION

EXERCISE 17.3

CONTINUED

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

434

PubsOnLine.com PART V

LISTING 17.2
‘Author: ‘Purpose: ‘Rules: ‘Revisions:

Continued

On Error GoTo PutDataErr Dim Dim Dim Dim Dim objLog As POLInterfaces.IWriteErrors lngNumber As Long strDescription As String objInbound As DNAPayload.Dataset 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 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 ‘Rules: Construction must be enabled for this component ‘Revisions: 2/4/00 Original m_Connect = pCtorObj.ConstructString End Sub

435

17
BUILDING THE PUBSONLINE.COM APPLICATION

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.

436

PubsOnLine.com 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 CDROM 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 CHAPTER 17
Dim Dim Dim Dim Dim Dim Dim Dim objLog As POLInterfaces.IWriteErrors lngNumber As Long strDescription As String objParams As DNAPayload.Dataset objReturn As DNAPayload.Dataset objDataObject As POLInterfaces.ITransact objCartObject As POLInterfaces.IData vData As Variant

437

‘Get the Object Context Dim objContext As COMSVCSLib.ObjectContext Set objContext = GetObjectContext ‘Create Payload Object 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

17
BUILDING THE PUBSONLINE.COM APPLICATION

438

PubsOnLine.com PART V

LISTING 17.3
End If

Continued

‘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 CHAPTER 17

439

Start

ASP Page calls ShowCart method

Add to Cart?

No

Update Cart Quantities

Yes

17
BUILDING THE PUBSONLINE.COM 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.

440

PubsOnLine.com 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 compatibility property and lost references to other projects in the system. Pay close attention to carefully setting compatibility and be prepared to resolve any missing references in the project.

Building the PubsOnLine.com Application CHAPTER 17

441

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 configuration.

17
BUILDING THE PUBSONLINE.COM 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.

442

PubsOnLine.com 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 generated 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 components 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 construction 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 CHAPTER 17

443

17
BUILDING THE PUBSONLINE.COM APPLICATION

FIGURE 17.19
Log events by subscribing to IWriteErrors.

FIGURE 17.20
Add all the data and business classes to Component Services.

444

PubsOnLine.com PART V

FIGURE 17.21
Enable construction for all data and business services.

TABLE 17.1

Construction Strings

Components
CBooks CCart CMembership DataServ.GetADSIAddress DataServ.GetADSIFriendlyName DataServ.PutADSIAddress

Constructor C:\inetpub\wwwroot\PubsOnLine

LDAP://machinename/ CN=,CN=Users,DC=domainname Provider=SQLOLEDB; Data Source=(local); Initial Catalog=PubsOnLine; UID=COMDATA;PWD=compassword

All other DataServ classes

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 CHAPTER 17

445

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 completed, we’ll examine some of the pages in the site.

EXERCISE 17.5 Creating the Web Site Interface
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.

17
BUILDING THE PUBSONLINE.COM 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 project. 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.

446

PubsOnLine.com 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 computer. 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 parameters 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 understand 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 CHAPTER 17
objReturn.LoadXSL m_WebSite & “\xsl\results.xsl” objReturn.XML2HTML objContext(“Response”).Write objReturn.HTML

447

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 system 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
BUILDING THE PUBSONLINE.COM APPLICATION

SYMBOLS
@TRANSACTION=NOT SUPPORTED directive (ASP), 291 @TRANSACTION=REQUIRED directive (ASP), 291 @TRANSACTION=REQUIRES NEW directive (ASP), 291 @TRANSACTION=SUPPORTED directive (ASP), 291

INDEX

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

450

ACID

ACID (Atomicity, Consistency, Isolation & Durability) MSDTC functions, 183 transaction context, 185-189 Action menu commands, New/Component, 46 Activate method, ObjectControl interface, 99-100 activating objects, 88-90 Quick Check exercise, 91-93 SetComplete method, 95-96 Activation tab (Component Services) application properties, 36-38 component properties, 45 Active Directory (Windows 2000), 12, 24-25 authentication of users, 12 domain component (DC), 215 organization (O), 216 organizational unit (OU), 216 Domain Name Service (DNS), 25 email manipulation, 12 enterprise database information, 12 installing, 24-25 LDAP, root, 214 pathnames, 213-214 common name (CN), 215 distinguished name (DN), 215 ports, 214

PubsOnLine.com Application, activating, 418 replacement of Security Accounts Manager (SAM), 12 Schema explorer, 217 secure logins, OpenDSObject method, 220 security, 12 features, 210 group policies, 212 Microsoft Installer (MSI), 211 single sign-ons (SSO), 211 user information, 212 users authentication, 12 personalization, 12 Active Server Pages, see ASP ActiveX controls, frontend applications creating, 319-320 event handling, 321-322 forms substitute, 320 lack of inheritance, 320 limitations of, 322 loading, 319-324 ActiveX Data Objects, see ADO actors project design, 59-60 PubsOnLine application, identification, 393-394

Add Procedure command (Tools menu), 50 AdjustBalance method, transaction example, 200-201 administering components (Component Services), 28-29 server privileges, PubsOnLine.com Application, 418 Administrator role, system applications, 40 ADO (ActiveX Data Objects), 334-337 Connection object, session pooling, 114 Record object, 334-337 Recordset object disconnected recordsets, 129-130 GetString method, 126-127 session pooling, 114 Stream object, 334-337 streaming XML, 14, 139-141 Web stores accessing (Exchange 2000 Server), 334, 337 querying (Exchange 2000 Server), 335-336 adOpenDynamic value (CursorType property), 124 adOpenForwardOnly value (CursorType property), 124

applications

451

adOpenKeyset value (CursorType property), 124 adOpenStatic value (CursorType property), 124 ADSI (Active Directory Services Interface), 213 authentication (Quick Check 8-1 exercise), 220-221 objects properties, 216-219 reference sets, 216-219 Advanced Server (Windows 2000), 11, 24 Advanced tab (Component Services) application properties, 38-39 component properties, 46 alternate application proxy servers, exporting process, 30 alternate path event flow, Use Cases project design, 64 alternate scenarios, Use Cases project design, 63 analyzing applications Component Load Balancing (NLB), 369 Network Load Balancing (NLB), 367-368 Web Application Stress tool (WAS), 363-367 Any Application role, system applications, 40

apartments components, synchronization control, 85 multi-threaded (MTA), 85 objects, concentric containers, 84-88 single-threaded (STA), 85 thread-neutral (TNA), 85 appending nodes, error handling (XML), 161-163 Application Center 2000, 369 Application object (Outlook 2000), 341 CreateItem method, 343 applications analysis tools Component Load Balancing (CLB), 369 Network Load Balancing (NLB), 367-368 Web Application Stress tool (WAS), 363-367 business services layer, deploying, 357-358, 362 client rich front-end ActiveX controls, 319-322 custom collections, 314-315 VB forms, 312 components, installing (COM Component Install Wizard), 46-48 creating (COM+ Application Install Wizard), 40-42 step-by step example, 49-51

data services layer, deploying, 357, 362 design actor identification, 59-60, 393-394 artifacts, 58 component definition, 415 database model, 407 functional requirements, assessment, 55-58 paper prototype, 403, 407 problem statements, 54-55, 392 Rational Unified Process (RUP), 54 requirements, 392-393 screen shots, 403, 407 system models, 408-415 Use Cases, 58-63, 393-402 development, evolution of, 84 distributed, 145-146 distribution application creation, 370-371 client software setups, 360-361 group policies, 361-362, 373-374 Microsoft Installer (MSI), 357-359 proxy setups, 359-360 setups creation, 371-373 software installation, 375

452

applications

error handling (XML), 161-163 front end creating (Microsoft Visual Modeler), 80-81 state layers, building, 327-330 group roles, 55 HTA, 324 deploying, 326 tags, 325-326 IIS 5 in-process versus outof-process, 282 server isolation levels, 283-284 MSMQ Object Model, creating, 258 naming guidelines, 268 records, updating, 142-143 recordset objects complex data binding, 317-319 simple data binding, 315-317 state support, 18 three-tier data partitions, 123-125 layers, 21-23 OOP, 23 tiered, creating (Exercise 4.1), 105-109 two-tier architecture, 19-21 user services layer, deploying, 359, 363

Array( ) function, variant arrays, 155-158 artifacts, project design, 58 as-soon-as-possible deactivation, object memory management, 17 ASP (Active Server Pages), 290 early scripting problems, 294-296 multi-page transactions, creating, 292-294 ObjectContext components (IIS Utilities), 290 @TRANSACTION= NOT SUPPORTED, 291 @TRANSACTION= REQUIRED, 291 @TRANSACTION= REQUIRES NEW, 291 @TRANSACTION= SUPPORTED, 291 objects accessing with COM+ components, 298-299 Request, 298-299 Response, 298-299 scriptless processing, 290 script classes, creating (VBScript), 294-296 Server object Execute method, 292-294 Transfer method, 292-294 ASPError object GetLastError method, 286-288 properties, 286-288

assertions, data components, 156 assessing functional requirements (project design), 57-58 asynchronous components, queued, 18 asynchronous processing, 256 components Microsoft Message Queue (MSMQ), 256-257 queued components (QC), 256, 265-270 message queuing, 14 atomicity, database transaction attribute, 182 authentication Active Directory Quick Check 8-1 exercise, 220-221 secure logins, 220 DCOM, 31 Kerberos protocol cloaking, 210 tickets, 210 public key encryption, 208-209 Security Support Provider Interface (SSPI), 209 Windows NT LAN Manager Security Support Manager, 209 automatic transactions, 18 error handling, 195-198 transactional components consistency bit, 192-198 done bit, 192-198

clients

453

B
BackUpREGDB method, COMAdminCatalog object, 379 basic path event flow, Use Case project design, 63 batch files, writing, 383-384 BeginAbortVariants method, IcrmCompensatorVariants interface, 245-246 BeginCommitVariants method, IcrmCompensatorVariants interface, 245-246 BeginPrepareVariants method, IcrmCompensatorVariants interface, 245 binary compatability, component debugging (Visual Basic), 354-355 BindingCollection object, 315-317 Body property (MSMQEvent object), 262-263 Boolean expressions, event filtering, 238 breakpoints, component debugging (Visual Basic), 354 building corporate portals, 350-351 databases, PubsOnLine.com Application, 419-425

models (Microsoft Visual Modeler), 70-81 transactions, 199-204 business services layer applications, deploying, 357-358, 362 data components, 151 PubsOnLine.com Application, creating, 436-440 three-tier applications, 21-23 transactional boundaries, 189-190 byte arrays, property bags, returning, 133-134

C
calling queued components (QC) new moniker, 268-270 queue moniker, 268-270 CanBePooled method, ObjectControl interface, 99 Catalog Administration class modules, wizard creation, 387-388 Component Services Administration Object Model, 378 COMAdminCatalog, 378-379 COMAdminCatalogCol lection, 380-381 COMAdminCatalogObj ect, 382-383 WSH, batch operation languages, 383-384

CCart class, ShowCart method, 436-440 CDO (Collaboration Data Objects), 336-337 certificates (security), 208 Microsoft Management Console (MMC), snap-in additions, 209 public key encryption, 208-209 champions functional requirements, assessment phase, 57-58 group roles, project design, 55 choose tag (XSL), 305-306 class modules (Catalog Administration Wizard), 387-388 classes events defining, 233-234 installing, 234 three-tier diagram, 69 client-side transactions (QC), 271 clients applications proxy setup, 359-360 software setup, 360-361 error handling messages, XML streams, 161-163 front-end applications ActiveX controls, 319-322 custom collections, 314-315 VB forms, 312

454

clients

HTA applications package deployments, 326 Web server deployments, 326 cloaking (Kerberos protocol), 210 Cluster Parameters tab, Network Load Balancing (NLB), 368 coarse components maintenance disadvantages, 153 performance disadvantages, 153 transactional boundaries, 186-189 versus fine-grain components, 152 code generation (Microsoft Visual Modeler), 78-79 collaboration applications Exchange 2000 Server email, 336-337 Web stores, 332-337 Outlook 2000 data views, 338 features, 338 forms, 338-339 Collaboration Data Objects, see CDO collisions causes, 143-144 disconnected recordsets, preventing, 142-143 firehose cursors, preventing, 142 record updates, preventing, 142-144 troubleshooting, 143-144

COM Component Install Wizard, 48 event classes, installing, 234 launching, 46 COM Internet Services, 32 COM+ (Component Object Model) applications, developmental evolution, 84 services application state support, 18 asynchronous components, 18 automatic transactions, 18 event support, 17 memory management, 17 multi-threaded apartments (MTA), 16-17 object pooling, 17 security, 18 versus MTS in applications development, 84 COM+ Application Install Wizard, 40-42 COM+ Explorer, see Component Services COM+ Services, Type Library, object context communication, 93-96 COMAdminCatalog object, 378 methods, 379 BackUpREGDB, 379 Connect, 379 ExportApplication, 379 GetCollection, 379

GetCollectionByQuery, 379 GetEventClassesForIID, 379 GetMultipleComponentsInfo, 379 ImportComponent, 379 InstallApplication, 379 InstallComponent, 379 InstallEventClass, 379 InstallMultipleComponents, 379 QueryApplicationFile, 379 RefreshComponents, 379 RestoreREGDB, 379 ServiceCheck, 379 ShutdownApplication, 379 COMAdminCatalogCollection object arguments, 380 Applications, 380 Components, 380 ComputerList, 380 DCOMProtocols, 380 ErrorInfo, 380 InProcServers, 380 InterfacesForComponent, 380 LocalComputer, 380 MethodsForInterface, 380 PropertyInfo, 380 PublisherProperties, 380 RelatedColectionInfo, 380 Roles, 380

components

455

RolesforComponents, 380 RolesForInterface, 380 RolesForMethod, 380 Root, 380 SubscriberProperties, 381 TransientSubscriptions, 381 UsersInRole, 381 methods GetCollection, 381 Populate, 381 commands Action menu, New/Component, 46 Project menu, References, 51 Tools menu, Add Procedure, 50 CommitRecordVariants method, IcrmCompensatorVariants interface, 245 common name (CN), Active Directory pathnames, 215 communicating object contexts, 93-96 Compensating Resource Manager, see CRM compiling source code (PubsOnLine.com Application), 440-442 complex binding, recordset objects (DataBindingBehavior object), 317-319 Component Load Balancing (CLB), 369

Component Services application properties Activation tab, 36-38 Advanced tab, 38-39 General tab, 34 Identity tab, 36 Queuing tab, 38 Security tab, 35 component properties Activation tab, 45 Advanced tab, 46 Concurrency tab, 46 General tab, 43 Security tab, 44 Transaction tab, 43 components administration, 28-29 listview, 29 treeview, 29 computer properties Default Properties tab, 30-32 Default Protocols tab, 32 Default Security tab, 32 General tab, 29 MSDTC tab, 30 My Computer Tasks tab, 33 Options tab, 29-30 launching, 28 transactional component properties, 184-185 user roles, 40 Component Services Administration Object Model, 378 roles, defining, 222

components administering (Component Services), 28-29 apartments, synchronization control, 85 application properties (Component Services) Activation tab, 36-38 Advanced tab, 38-39 General tab, 34 Identity tab, 36 Queuing tab, 38 Security tab, 35 applications, installing (COM Component Install Wizard), 46-48 ASP objects, accessing, 298-299 asynchronous processing Microsoft Message Queue (MSMQ), 256-257 queued components (QC), 256, 265-270 automatic transactions, 18 component properties (Component Services) Activation tab, 45 Advanced tab, 46 Concurrency tab, 46 General tab, 43 Security tab, 44 Transaction tab, 43 computer properties (Component Services) Default Properties tab, 30-32 Default Protocols tab, 32

456

components

Default Security tab, 32 General tab, 29 MSDTC tab, 30 My Computer Tasks tab, 33 Options tab, 29-30 configured, 86-87 constructors, passing, 239 contexts versus context wrappers, 85 non-configured, 86-87 PubsOnLine.com Application construction strings, 444 creating, 425-428 deploying, 440-442 queued, 18 state information, Shared Property Manager (SPM), 102-104 threads multi-thread apartment (MTA), 16-17 single-thread apartment (STA), 16-17 thread-neutral apartment (TNA), 16-17 transactional building, 199-204 voting process, 190-195 Visual Basic breakpoints, 354 debugging, 354-355 Visual InterDev, debugging, 355 concentric containers (objects) apartments, 84-88 contexts, 84-88 processes, 84-88

Concurrency tab (Component Services component property), 46 conditional compilation, component debugging (Visual Basic), 355 conditions, use case project design, 62-63 configured components, 86-87 Connect method (COMAdminCatalog object), 379 Connection object (ADO), session pooling, 114 connection strings (MTS) versus constructors, 238 consistency, database transaction attribute, 182 consistency bit, transactional components, 192-198 construction strings (PubsOnLine.com Application), 444 constructors, 239 components, passing, 239 IObjectConstruct interface, 239-240 IObjectConstructString object, 239-240 Quick Check 9-1 exercise, 240-241 versus connection strings (MTS), 238 versus Shared Property Manager (SPM), 238 versus Universal Data Link (UDL) files, 238

ContactItem object (Outlook 2000), 345 context wrappers versus contexts, 85 contexts components configured, 86-87 non-configured, 86-87 GetObjectContext( ) function, 94-95 objects concentric containers, 84-88 referencing, 93-96 versus context wrappers, 85 controlling pools (OLEDB), 115-117 Controls collection (Outlook 2000), 342 corporate portals (Web pages), 348-349 building, 350-351 corporate standards, polymorphism, developing, 164 CReadData template (Visual Basic), PubsOnLine.com Application, 428-433 Create Stream method, XML output streams, 172-173 CreateObject function versus New keyword, property bags, 131 CreateObject method, WScript object (WSH), 384

CWriteData template

457

CreateShortcut member, Shell object (WSH), 385 creating applications COM+ Application Install Wizard, 40-42 MSMQ Object Model, 258 step-by-step example, 49-51 business services layer (PubsOnLine.com Application), 436-440 client software setups in applications, 360-361 components (PubsOnLine.com Application), 425-428 data layer in distributed applications, 145-146 data services layer (PubsOnLine.com Application), 428-436 event subscribers (New Subscription Wizard), 235-236 group policies, application deployment, 361-362 paper prototypes, Use Cases project design, 65 proxies in client-rich frontend applications, 359-360 queues (MSMQ Message Queuing explorer), 257 standard function signatures (abstract classes), 165-167 tiered applications, 105-109

transactional Web pages (IIS 5), 290-294 Web sites, PubsOnLine.com Application, 445-447 CRM (Compensating Resource Manager), 242 duplicate log records, 249-252 flags (transactions), 244 IcrmCompensatorVariants interface AbortRecordVariants method, 245-246 BeginAbortVariants method, 245-246 BeginCommitVariants method, 245-246 beginPrepareVariants method, 245 CommitRecordVariants method, 245 EndAbortVariants method, 245-246 EndCommitVariants method, 245-246 endPrepareVariants method, 245-246 PrepareRecordVariants method, 245 SetLogControlVariants method, 245 Quick Check 9-2 exercise, 247-249 Recovery In Progress error, 249 system crashes, recovery from, 249 system-wide error logs, creating, 249-252

transactions isolation, 249 success/failure voting process, 245 two-phase commit capabilities, 242 Worker commit/abort actions, 242 designing, 242-243 durable logs, 242-243 transaction processing, 242 write-ahead operations, 244 CRMClerk object, 243 ForceLog method, 244 RegisterCompensator method, 243-244 cursors firehose, 125 two-tier applications, 19 cursors (ADO), CursorType property, 123 adOpenDynamic value, 124 adOpenForwardOnly value, 124 adOpenKeyset value, 124 adOpenStatic value, 124 custom collections, frontend applications (ICollection interface), 314-315 customer information repository (Active Directory), 212 CWriteData template (Visual Basic), PubsOnLine.com Application, 433-436

458

data

D
data data components HTML display (DNA Payload), 174-175 returning (DNA Payload), 173-174 parsing (DNA Payload), 173-174 partitions, transporting (three-tier applications), 123-125 payloads, three-tier applications, 125-126 transports delimited strings, 126-127 disconnected recordsets, 129-130 property bags, 131-134 SOAP protocol, 141 Stream object (ADO), 139-141 three-tier applications, 125-126 variant arrays, 127-128 XML, 134-138 data binding, recordset objects BindingCollection object, 315-317 DataBindingBehavior object, 317-319 Data Center Server (Windows 2000), 11 data components assertions, 156 business services layer, 151

coarse, maintenance/performance disadvantages, 153 data HTML display (DNA Payload), 174-175 returning (DNA Payload), 173-174 transformation (DNA Payload), 167-169 DebugAssert( ) method, 156 design goals, 150 encapsulation, 150-154 fine-grain, 152 function of, 150 parameters passing, 154-161 passing (DNA Payload), 170-173 stored procedures, repeated code, 152 strong function signatures, 154 variant arrays, data, passing, 155-158 XML parameters, passing, 158-161 data device services layer, three-tier applications, 21-23 data layer, distributed applications, creating, 145-146 data services layer applications, deploying, 357, 362 fine-grain components usage, 153 PubsOnLine.com Application, creating, 428-436

data source proxy object, see DPO database models entities, 66 PubsOnLine application, 407 relationships, 66 databases ACID attributes, 183 batch updates, disconnected recordsets, 142-143 connections, session pooling, 114 distributed transactions, two-phase commit, 183 PubsOnLine.com Application creating, 419-425 shopping carts, 419425 records, collision prevention, 142-144 rollback transactions, 182 transaction attributes atomicity, 182 consistency, 182 durability, 182 isolation, 182 two-tier applications access, 19 cursors, 19 maintenance difficulties, 20-21 record locking, 19 scalability issues, 20 site design disadvantages, 20

distributed applications

459

DataBindingBehavior object, 317-319 Dataset object (DNA Payload) methods LoadXSL, 174-175 XML2HTML, 174-175 properties, 169 DCOM (Distributed COM), 30 authentication levels, 31 firewalls, 32 impersonation levels, 32 Internet services, 32 port usage, 32 Deactivate method, ObjectControl interface, 99-100 deactivating objects, 88-90 SetAbort method, 95-96 DebugAssert( ) method, 156 debugging components Visual Basic, 354-355 Visual InterDev, 355 declarative security roles, access permissions, 222 versus programmatic security, 226 Default Properties tab (Component Services computer property), 30-32 Default Protocols tab (Component Services computer property), 32 Default Security tab (Component Services computer property), 32

defining event classes, 233-234 delimited strings characteristics, 126-127 returning, 126-127 XML, performance characteristics, 126 deploying applications business services layer, 357-358, 362 data services layer, 357, 362 user services layer, 359, 363 components (PubsOnLine.com Application), 440-442 HTA applications, 326 designing applications functional requirements, 55-58 problem statements, 54-55 Rational Unified Process (RUP), 54 CRM Worker, 242-243 data components, goals, 150 projects Actors, 59-60 artifacts, 58 Unified Modeling Language (UML), 59-60 use cases, 58-60 PubsOnLine application actor identification, 393-394 database model, 407

paper prototype, 403, 407 problem statement, 392 requirements, 392-393 screen shots, 403, 407 system models, 408-415 use cases, 393-402 queued components (QC), 266-268 stored procedures, 151 digital dashboards, Web pages, 348-349 digital signatures, public key encryption, 209 DirectCaller object, programmatic security, 225 disconnected recordsets, 125 advantages, 134 batch updates, 142-143 characteristics, 129-130 disadvantages, 134 record updates, 142-143 returning, 129-130 DisconnectObject method, WScript object (WSH), 384 displaying data, XML/HTML conversion (DNA Payload), 174-175 distinguished name (DN), Active Directory pathnames, 215 distributed applications data layer, creating, 145-146 polymorphism, standardization features, 163-164 security, 208

460

Distributed COM

Distributed COM, see DCOM distributed transactions, 183 distributing applications application creation, 370-371 group policy creation, 373-374 setups creation, 371-373 software installation, 375 dllhost.exe, processes, object management, 84-85 DLLs (dynamic link libraries), installing, 48 DNA Payload data components data transformation, 167-169 data, HTML display, 174-175 data, returning, 173-174 parameters, passing, 170-173 Dataset object, 427-436 methods, 170 properties, 169 Field object, 427-436 parameters, passing, 170 properties, 170 Recordset conversion, 171 recordset, XML output stream, 172-173 returned streams HTML display, 174-175 parsing, 173-174

documentation, use case project design, 60-61 domain component (DC), Active Directory, 215 organization (O), 216 organizational unit (OU), 216 domain environments (MSMQ), 257 Domain Name Service (DNS), Active Directory, 25 done bit, transactional components, 192-198 DPO (data source proxy object), 114 pools, destruction of, 115-117 session pooling, 114 duplicate log records (CRM), 249-252 durability, database transaction attribute, 182 durable logs (CRM Worker), 242-243

E
e-commerce applications, creating, 105-109 early bound events, 232 Echo method, WScript object (WSH), 384 element tag (XSL), 306 email Exchange 2000 Server, Collaboration Data Objects (CDO), 336-337 Outlook 2000, request forms, creating, 346-348

enabling event subscribers, 236 encapsulation data components, 150-154 stored procedures class module example, 151 data components, 151-154 EndAbortVariants method, IcrmCompensatorVariants interface, 245-246 EndCommitVariants method, IcrmCompensatorVariants interface, 245-246 EndPrepareVariants method, IcrmCompensatorVariants interface, 245-246 enterprise applications Active Directory, 12 Network Load Balancing (NLB), 16 scaling, 16 entities, database models, 66 Environment member, Shell object (WSH), 385 error handling automatic transactions, 195-198 XML nodes, appending, 161-163 error logs, creating (CRM), 249-252

front-end applications

461

error messages, Web pages, generating (IIS 5), 285-288 events ActiveX controls, handlers, 321-322 classes defining, 233-234 installing, 48 interfaces, 233-234 COM+ services, 17 early bound, 232 Item object (Outlook 2000), 341-342 loosely coupled, 17 publishers, 232 subscribers, 232 OnClick transaction example, 203-204 publishers, 17 firing, 237 subscribers, 17 creating (New Subscription Wizard), 235-236 enabling, 236 filtering, 238 implementing, 234-236 tightly bound, 232 exception path event flow, use case project design, 64 exception scenarios, use case project design, 63 exceptions (QC), 272 Exchange 2000 Server collaboration email, 336-337 features, 332 Web stores, 332-337

email, Collaboration Data Objects (CDO), 336-337 Web stores ActiveX Data Objects (ADO), 334-337 browser access, 332-334 ExpandEnvironmentStrings member, Shell object (WSH), 385 ExportApplication method (COMAdminCatalog object), 379 exporting applications client software setups, 360-361 group policies, 361-362 Microsoft Installer (MSI), 357-359 proxy setups, 359-360 eXtensible Markup Language, see XML eXtensible Style Language, see XSL

F
facilitated sessions, project design requirements, 56 Field object (DNA Payload) parameters, passing, 170 properties, 170 Recordset conversion, 171 filtering events in subscriptions, 238

FinalClientRetry method, IPlaybackControl interface (QC), 272 FinalServerRetry method, IPlaybackControl interface (QC), 272 fine-grain components data services layer, 153 transactional boundaries, 189-190 versus coarse components, 152 firehose cursors, 125 record updates, 142 XML, returning, 135-136 firewalls (DCOM), 32 firing events, 237 flags, transactions (CRM), 244 flow charts, use case project design, 64 Folders collection (Outlook 2000), GetDefaultFolder method, 344 for-each tag (XSL), 305 ForceLog method (CRMClerk object), 244 forms ActiveX controls, design of, 320 client rich front-end applications, 312 front-end applications ActiveX controls creating, 319-320 forms substitute, 320-322 lack of inheritance, 320 limitations of, 322 loading, 319-324

462

front-end applications

forms usage, 312 ICollection interface methods, 314-315 Microsoft Visual Modeler, 80-81 state layers, building, 327-330 state/workflow layer (Win32 clients), 312-313 function signatures data components, parameters, passing, 154 Intellisense, 154 standards, creating (polymorphism), 165-167 functional requirements (project design) assessing, 57-58 facilitated sessions, 55-56 prioritizing, 56-57

G
General tab (Component Services) application properties, 34 component properties, 43 computer properties, 29 generating custom error messages on Web pages (IIS 5), 285-288 GetBalance method, transaction example, 201-202 GetCollection method COMAdminCatalog object, 379 COMAdminCatalogCollect ion object, 381

GetCollectionByQuery method (COMAdminCatalog object), 379 GetDefaultFolder method, constants (Outlook 2000), 344 GetEventClassesForIID method (COMAdminCatalog object), 379 GetLastError method (ASPError object), 286-288 GetMultipleComponentsInfo method (COMAdminCatalog object), 379 GetObject method, WScript object (WSH), 384 GetObjectContext( ) function, 94-95 GetString method, Recordset object (ADO), 126-127 group policies Active Directory, 212 client applications, creating, 361-362 groupware Exchange 2000 Server, 332 email, 336-337 Web stores, 332-337 Outlook 2000 data views, 338 forms, 338-339

H-I
handling events (ActiveX controls), 321-322 header sections, Use Case project design, 61 Host Parameters tab, Network Load Balancing (NLB), 368 HTA (HTML Application), 324 deploying, 326 tags, 325-326 HTML (Hypertext Markup Language) to XML transformation, 136-138, 174-175 ICollection interface methods Add, 314-315 Count, 314-315 Item, 314-315 Remove, 314-315 IcrmCompensatorVariants interface AbortRecordVariants method, 245-246 BeginAbortVariants method, 245-246 BeginCommitVariants method, 245-246 BeginPrepareVariants method, 245 CommitRecordVariants method, 245 EndAbortVariants method, 245-246 EndCommitVariants method, 245-246 EndPrepareVariants method, 245-246

Item object

463

PrepareVariants method, 245 SetLogControlVariants method, 245 identifying actors in system projects, 59-60 functional requirements in project design, 55-57 Identity tab (Component Services application property), 36 if tag (XSL), 305 IIS 5 (Internet Information Server version 5), 282 applications in-process versus outof-process, 282 server isolation levels, 283-284 ASP errors, ASPError object, 286-288 COM+ integration, 282 custom error messages, generating, 285-288 HTTP errors, 285 IIS Utilities package, transactional Web pages, 290 in-process components, unloading, 284 Internet Services Manager, 282 Microsoft Management Console (MMC) application, 13 new features, 282 previous versions, 282-283 scriptless ASP processing, 290 transactional Web pages, creating, 290-294

Utilities package, ASP ObjectContext components, 290-291 Windows DNA support, 12 impersonation levels (DCOM), 32 implementing event subscribers, 234-236 ImportComponent method (COMAdminCatalog object), 379 in-process applications versus out-of-process applications, 282 in-process components, unloading (IIS 5), 284 inheritance (ActiveX controls), 320 Inspector object (Outlook 2000), 342 InstallApplication method (COMAdminCatalog object), 379 InstallComponent method (COMAdminCatalog object), 379 InstallEventClass method (COMAdminCatalog object), 379 installing Active Directory, 24-25 PubsOnLine.com Application, 418 components in installations (COM Component Install Wizard), 46-48 DLLs, 48 event classes, 48 COM Component Install Wizard, 234

InstallMultipleComponents method (COMAdminCatalog object), 379 instances activation, 88-93 deactivation, 88-90 New keyword versus CreateObject function, 131 Intellisense, strong function signatures, 154 interfaces events classes, 233-234 function signatures, standardization of, 165-167 Internet Explorer, XML output, 14, 136 Internet Information Server version 5, see IIS 5 Internet services (DCOM), 32 IObjectConstruct interface, 239-240 IObjectConstructString object, 239-240 IPlaybackControl interface (QC), exception classes, 272 isolated transactions (CRM), 249 isolating IIS applications, server levels, 283-284 isolation, database transaction attribute, 182 Item object (Outlook 2000), 341-342

464

just-in-time activation

J-K-L
just-in-time activation (JIT), 17, 89-90 Kerberos protocol, 210 launching COM Component Install Wizard, 46 Component Services, 28 LDAP (Lightweight Directory Access Protocol), 214 Active Directory, 214 objects, accessing, 216 pathnames, 214 root, 214 Lightweight Directory Access Protocol (LDAP), 12, 214 Listener (QC), 266 loading ActiveX controls in front-end applications, 319-324 LoadXSL method (Dataset object), 174-175 logical models goals, 67 patterns, 67 UML, 68 loosely coupled events (LCE), 17 publishers, 232 subscribers, 232

M
MailItem object (Outlook 2000), 345-346 maintenance in two-tier applications, 20-21 manual transactions, transactional components, 195 marshaling variant arrays, 127-128 memory, object management as-soon-as-possible deactivation, 17 just-in-time activation, 17 message queues, 263-264 asynchronous communications, 14 methods Activate, 99-100 AdjustBalance, transaction example, 200-201 Application object (Outlook 2000), CreateItem, 343 ASPError object, GetLastError, 286-288 CanBePooled, 99 COMAdminCatalog object BackupREGDB, 379 Connect, 379 ExportApplication, 379 GetCollection, 379 GetCollectionByQuery, 379 GetEventClassesForIID, 379 GetMultipleComponentsInfo, 379

ImportComponent, 379 InstallApplication, 379 InstallComponent, 379 InstallEventClass, 379 InstallMultipleComponents, 379 QueryApplicationFile, 379 RefreshComponents, 379 RestoreREGDB, 379 ServiceCheck, 379 ShutdownApplication, 379 COMAdminCatalogCollection object GetCollection, 381 Populate, 381 CreateStream, 172-173 Dataset object LoadXSL, 174-175 XML2HTML, 174-175 Dataset object (DNA Payload), 170 Deactivate, 99-100 Debug Assert, 156 ForceLog (CRMClerk object), 244 GetBalance, transaction example, 201-202 MSMQQueueInfo object LookUpQueue, 259-260 Open, 260-261 Next, 260 Reset, 260 polymorphism, 164 RegisterCompoensator (CRMClerk object), 243-244

MSMQMessage object

465

SetAbort, 95-96 SetComplete, 95-96 Transfer, transaction example, 202-203 Microsoft Cluster Server versus NLB, 16 Microsoft Distributed Transaction Coordinator, see MSDTC Microsoft Installer (MSI) Active Directory, 211 applications, distribution, 357-359 Microsoft Management Console (MMC) certificates, snap-in additions, 209 Internet Information Server (IIS), 13 Microsoft Message Queue, see MSMQ Microsoft Transaction Server, see MTS Microsoft Visual Modeler applications, front end creation, 80-81 code generation, 78-79 logical models, creating, 68 models, building, 70-81 objects classes, creating, 74-76 methods, creating, 74-76 properties, creating, 74-76 reverse engineering, 71-73 round-trip engineering, 71-73

modeling databases entities, 66 relationships, 66 logical model goals, 67 patterns, 67 UML, 68 Microsoft Visual Modeler, 70-81 project design (UML), 59-60 monikers (queued components) new, 268-270 queue, 268-270 monitoring transactions (Component Services explorer), 198 MSDTC (Microsoft Distributed Transaction Coordinator), 183 transactional components Resource Dispensers, 185 Resource Managers, 185 transactions, monitoring statistics, 198 two-phase commit, 183 MSMQ (Microsoft Message Queue), 14, 25, 256 asynchronous processing, 256-257 benefits, 256 domain environments, 257 installations, planning guidelines, 256

limitations, 264 Object Model applications, creating, 258 message/queue management, 258 MSMQApplication object, 258 MSMQEvent object WithEvents keyword, 261-262 MSMQMessage object Body property, 262-263 MSMQQuery object LookUpQueue method, 259-260 MSMQQueueInfo object Open method, 260-261 MSMQQueueInfos object Next method, 260 Reset method, 260 queues, creating (Message Queuing explorer), 257 Quick Check 10-1 exercise, 263-264 versus queued components (QC), 264 MSMQApplication object, 258 MSMQEvent object, WithEvents keyword, 261-262 MSMQMessage object, Body property, 262-263

466

MSMQQuery object

MSMQQuery object, methods LookUpQueue, 259-260 Open, 260-261 Next, 260 Reset, 260 MTS (Microsoft Transaction Server), 84 multi-page transactional Web pages, creating (IIS 5), 292-294 multi-threaded apartments (MTA), 16-17, 85 multi-valued properties, ADSI objects, 218-219 My Computer Tasks tab (Component Services computer property), 33

New keyword versus CreateObject function, property bags, 131 new moniker (QC), 268-270 New Subscription Wizard, event subscribers, creating, 235-236 New/Component command (Action menu), 46 nodes, appending (XML), 161-163 non-configured components, 86-87

O
Object Model (MSMQ) MSMQApplication object, 258 MSMQEvent object, WithEvents keyword, 261-262 MSMQMessage object, Body property, 262-263 MSMQQuery object LookUpQueue method, 259-260 Open method, 260-261 Next method, 260 Reset method, 260 object pooling, 17 ObjectControl interface methods Activate, 99-100 CanBePooled, 99 Deactivate, 99-100 Quick Check exercise, 100-101

N
NameSpace object (Outlook 2000), 343 naming applications, guidelines, 268 network cards, Network Load Balancing (NLB), 367 Network Load Balancing (NLB) activating, 367-368 Cluster Parameters tab, 368 Host Parameters tab, 368 network cards, 367 Port Rules tab, 368 versus Microsoft Cluster Server, 16

objects activation, 88-90 Quick Check exercise, 91-93 SetAbort method, 95-96 SetComplete method, 95-96 Active Directory, accessing (LDAP), 216 ADSI properties, 216-219 reference sets, 216-219 as-soon-as possible deactivation, 17 Catalog Administration, 378 COMAdminCatalog, 378-379 COMAdminCatalogCol lection, 380-381 COMAdminCatalogObj ect, 382-383 classes, creating (Microsoft Visual Modeler), 74-76 concentric containers apartments, 84-88 contexts, 84-88 processes, 84-88 contexts, referencing, 93-96 deactivation, 88-90 DNAPayload Dataset class, 427-436 Field class, 427-436 instantiation, New keyword versus CreateObject function, 131

parsing returned streams

467

just-in-time activation (JIT), 17, 89-90 methods, creating (Microsoft Visual Modeler), 74-76 ObjectControl interface Activate method, 99-100 CanBePooled method, 99 Deactivate method, 99-100 Quick Check exercise, 100-101 polymorphism, 164 processes (dllhost.exe), 84-85 properties, creating (Microsoft Visual Modeler), 74-76 property bags, 131 byte arrays, returning, 133-134 persistence, 132 stateful, 98 stateless, 96-98 transaction context, 185-189 transactional components, 184-185 WSH (Windows Scripting Host) Shell, 385 WScript, 384-385 XML, returning, 135-136 OLEDB (Object Linking and Embedding Database) pools, controlling, 115-117 providers, searching (REGEDIT utility), 117-120

session pooling benefits, 114 implementing (Quick Check exercise), 120-122 Registry tuning, 117-120 OnClick event, transaction example, 203-204 Online Flower Shop (QC) data components creation, 275-276 database creation, 273-274 email component creation, 274-275 Web site creation, 277-278 Online Shopping Cart (XSL) cart database creation, 306-307 components creation, 307 Web site creation, 307-309 OOP (object-oriented programming), 23 OpenDSObject method, secure logins (Active Directory), 220 OriginalCaller object, programmatic security, 225 out-of-process applications versus in-process applications, 282 Outlook 2000 collaboration data views, 338 forms, 338-339 corporate portals, 348-349 building, 350-351

digital dashboards, 348-349 email request forms exercise (Quick Check 13-2), 346-348 object model Application object, 341 CreateItem method, 343 ContactItem object, 345 Controls collection, 342 Folders collection, 344 Inspector object, 342 Item object, 341-342 MailItem object, 345346 NameSpace object, 343 Page object, 342 TaskItem object, 345 VBScript, 340-341 Visual Basic, 340-341

P
packages, HTA applications, deploying, 326 Page object (Outlook 2000), 342 paper prototypes PubsOnLine application, 403, 407 Use Case project design, 65 parameters, data components, passing (DNA Payload), 170-173 parsers (XML), 140 parsing returned streams (DNA Payload), 173-174

468

partitions

partitions, three-tier applications, 21-23, 123-125 passing constructors to components, 239 parameters in data components (DNA Payload), 170-173 query parameters in data components, 154-161 pathnames (Active Directory), 213-214 common name (CN), 215 distinguished name (DN), 215 ports, 214 patterns, logical model, 67 payloads data sets, three-tier applications, 125-126 schema definitions, 126 XML, 158-161 perfect scenarios, use case project design, 63 Performance Monitor, session pooling, 117 persistence, property bag objects, 131-134 platforms, procedure calls (SOAP), 141 player (QC), 266 polymorphism corporate standards, developing, 164 function signatures, standardizing, 165-167 standardization features, 163-164

pools (OLEDB) access credentials, 116 database security, 117 logins, 116 SQL Server logins, 116 controlling, 115-117 Populate method (COMAdminCatalogColl ection object), 381 Popup member, Shell object (WSH), 385 Port Rules tab, Network Load Balancing (NLB), 368 post-conditions, use case project design, 62-63 pre-conditions, use case project design, 62-63 PrepareRecordVariants method, IcrmCompensatorVariants interface, 245 prioritizing functional requirements in project design, 56-57 problem statements project design, 54-55 PubsOnLine application, 392 procedure calls, crossplatform (SOAP), 141 processes dllhost.exe, object management, 84-85 objects, concentric containers, 84-88

Professional Workstation (Windows 2000), 11 programmatic security DirectCaller object, 225 OriginalCaller object, 225 SecurityCallContext object, 223-225 SecurityIdentity object, 226 versus declarative security, 226 Project menu commands, References, 51 projects design Actors, 59-60 artifacts, 58 functional requirements, 55-58 problem statements, 54-55 three-tier diagram, 69 Unified Modeling Language (UML), 59-60 use cases, alternate path event flow, 64 use cases, alternate scenarios, 63 use cases, basic path event flow, 63 use cases, conditions, 62-63 use cases, documenting, 60-61 use cases, exception path event flow, 64 use cases, exception scenarios, 63

QC (queued components)

469

use cases, flow charts, 64 use cases, header sections, 61 use cases, paper prototypes, 65 use cases, perfect scenarios, 63 use cases, purpose statements, 62 use cases, rules, 62-63 group roles, 55 logical modeling goals, 67 patterns, 67 UML, 68 properties ADSI objects multi-valued, 218-219 single-valued, 218-219 Dataset object (DNA Payload), 169 Field object (DNA Payload), 170 WScript object (WSH), 385 property bags byte arrays, returning, 133-134 characteristics, 131-134 New keyword versus CreateObject functions, 131 object properties management, 132 proxies, client-rich front end applications, creating, 359-360

proxy servers, exporting process, 30 public key encryption digital signatures, 209 private keys, 208-209 public keys, 208-209 publishers events, firing, 237 loosely coupled events (LCE), 232 PubsOnLine.com Application actors Administrator, 393-394 Customer, 393-394 business services layer, creating, 436-440 CCart class, ShowCart method, 436-440 components construction strings, 444 creating, 425-428 deploying, 440-442 data services layer, creating, 428-436 database creating, 419-425 shopping carts, 419-425 database model, 407 development environments Active Directory activation, 418 administrator privileges, 418 SQL Server, 418 Visual Basic, 418 Visual InterDev, 418

DNAPayload object Dataset class, 427-436 Field class, 427-436 paper prototype, 403, 407 problem statement, 392 requirements, 392 membership and personalization, 393 promotions, 393 site analysis, 393 screen shots, 403, 407 source code, compiling, 440-442 system models, 408 three-tier, 408-415 use cases, 393-394 Add Book to Cart, 397-399 Checkout, 401-402 Log In, 394-396 View Cart, 399-400 Visual Basic CReadData template, 428-433 CWriteData template, 433-436 Web site, creating, 445-447 purpose statements, use case project design, 62

Q
QC (queued components), 18, 256 calling via new moniker, 268-270 via queue moniker, 268-270

470

QC (queued components)

design guidelines, 266-268 exception classes FinalClientRetry, 272 FinalServerRetry, 272 Listener, 266 Online Flower Shop exercise data components creation, 275-276 database creation, 273-274 email component creation, 274-275 Web site creation, 277-278 Player, 266 Recorder, 265-266 transactions client-side, 271 server-side, 272 versus Microsoft Messaging Queue (MSMQ), 264-265 QC Trusted User role, 40 query parameters, data components, passing, 154-161 QueryApplicationFile method (COMAdminCatalog object), 379 querying Web stores, ActiveX Data Objects (ADO), 335-336 queue moniker, 268-270 queued components, see QC queues, creating (MSMQ Message Queuing explorer), 257

Queuing tab (Component Services application property), 38 Quick Check exercises constructors (9-1), 240-241 CRM (9-2), 247-249 email request forms (13-2), 346-348 message queues (10-1), 263-264 simple components (10-2), 270-271 transactional Web pages (11-2), 297-298 Web stores, accessing (13-1) (Exchange 2000 Server), 337 WSH application shutdowns (15-3), 386-387 Quit method, WScript object (WSH), 384

R
Rational Unified Process, see RUP Reader role, system applications, 40 Record object (ADO), 334-337 record-locking, two-tier applications, 19 Recorder (QC), 265-266 records, collision prevention, 142-144

Recordset object (ADO) disconnected recordsets, 129-130 methods, GetString, 126-127 session pooling, 114 recordset objects complex data binding, 317-319 disconnected, 125 output streams, creating (CreateStream method), 172-173 simple data binding, 315-317 Recovery in Progress error (CRM), 249 reference sets (ADSI), 216-219 References command (Project menu), 51 referencing objects, contexts, 93-96 RefreshComponents method (COMAdminCatalog object), 379 RegDelete member, Shell object (WSH), 385 REGEDIT utility, OLEDB providers, searching, 117-120 RegisterCompensator method (CRMClerk object), 243-244 Registry, session pooling, tuning, 117-120 RegRead member, Shell object (WSH), 385 RegWrite member, Shell object (WSH), 385

sending email

471

relationships, database models, 66 repeated code alternatives, 152 coarse components, 152-153 fine-grain components, 152 Request object (ASP), 298-299 Resource Dispensers (MSDTC), 185 Resource Managers (MSDTC), 185 Response object (ASP), 298-299 RestoreREGDB method (COMAdminCatalog object), 379 returning byte arrays from property bags, 133-134 data in data components (DNA Payload), 173-174 delimited strings, 126-127 disconnected recordsets, 129-130 variant arrays, 127-128 XML from COM+ objects, 135-136 from Stream object (ADO), 139-141 reverse engineering (Microsoft Visual Visual Modeler), 71-73 roles declarative security, access permissions, 222 programmatic security, 223-225

rollbacks, transaction failures, 182 root templates, XSL style sheets, 302-304 round-trip engineering (Microsoft Visual Visual Modeler), 71-73 rules, Use Case project design, 62-63 Run member, Shell object (WSH), 385 RUP (Rational Unified Process), 54

S
scalability enterprise applications, 16 two-tier applications, 20 Schema explorer (Active Directory), 217 screen shots, PubsOnLine application, 403, 407 script classes (ASP), creating (VBScript), 294-296 searching OLEDB providers (REGEDIT utility), 117-120 security Active Directory, 12 COM+ services, 18 declarative roles, 222 versus programmatic, 226 distributed applications certificates, 208 famous breaches, 208

Kerberos protocol cloaking, 210 tickets, 210 programmatic DirectCaller object, 225 OriginalCaller object, 225 SecurityCallContext object, 223-225 SecurityIdentity object, 226 versus declarative, 226 Security Support Provider Interface (SSPI), 209 server impersonations, 208 strategies, 226 Visual InterDev, component debugging, 355 Windows 2000, Active Directory, 210-212 Windows NT LAN Manager Security Support Provider (NTLMSSP), 209 Security Support Provider Interface (SSPI), 209 Security tab (Component Services) application properties, 35 component properties, 44 SecurityCallContext object, programmatic security, 223-225 SecurityIdentity object, programmatic security, 226 self-defined payloads, 126 sending email, Collaboration Data Objects (CDO), 336-337

472

Server Applications role

Server Applications role, system applications, 40 Server object (ASP) Execute method, 292-294 Transfer method, 292-294 server-side transactions (QC), 272 servers administrator privileges (PubsOnLine.com Application), 418 impersonation, security breaches, 208 ServiceCheck method (COMAdminCatalog object), 379 session pooling (OLEDB), 114 access credentials, 116 database security, 117 logins, 116 SQL Server logins, 116 benefits, 114 system size criteria, 120 database connections, 114 DPO, 114 formulaic calculations, 115-117 implementing (Quick Check exercise), 120-122 tracking (Performance Monitor), 117 tuning (Registry), 117-120 SetAbort method, object deactivation, 95-96 SetComplete method, object activation, 95-96

SetLogControlVariants method, IcrmCompensatorVariants interface, 245 setting server isolation levels (IIS 5), 283-284 Shared Property Manager (SPM) application state support, 18 object hierarchy, 102 SharedProperty, 103 SharedPropertyGroup, 102 SharedPropertyGroup Manager, 102 Quick Check exercise, 103-104 stateful components, management of, 102-104 versus constructors, 238 SharedProperty object (SPM), 103 SharedPropertyGroup object (SPM), 102 SharedPropertyGroupManager object (SPM), 102 Shell object (WSH) members, 385 shopping carts, PubsOnLine.com Application, 419-425 ShowCart method, CCart class (PubsOnLine.com Application), 436-440 ShutdownApplication method (COMAdminCatalog object), 379

simple binding, BindingCollection object, 315-317 Simple Object Access Protocol (SOAP), 141 single sign-ons (SSO), Active Directory, 211 single-threaded apartments (STA), 16-17, 85 single-valued properties, ADSI objects, 218-219 SOAP (Simple Object Access Protocol), 141 software, client applications, creating, 360-361 source code, compiling (PubsOnLine.com Application), 440-442 SpecialFolders member, Shell object (WSH), 385 SQL Server (Windows 2000), 26 database, creating (PubsOnLine.com Application), 419-425 SQL statements versus stored procedures, 151 stakeholders functional requirements, assessment phase, 57-58 group roles, 55 PubsOnLine application, 392 membership and personalization, 393 promotions, 393 site analysis, 393 standards, function signatures, creating (polymorphism), 165-167

three-tier applications

473

state layers, applications, building, 327-330 state support, Shared Property Manager (SPM), 18 state/workflow layer, front-end applications (Win32 clients), 312-313 stateful objects, 98 Shared Property Manager (SPM), 102-104 stateless objects, 96-98 stored procedures access restrictions, business/user services layers, 151 data components encapsulation, 151-154 repeated code, 152 design, 151 encapsulation, class module example, 151 versus SQL statements, 151 storyboards, see paper prototypes Stream object (ADO), 334-337 data schema section, 139 XML, returning, 139-141 streams (XML), 14 client error handling, 161-163 creating (CreateStream method), 172-173 parameters, passing, 160-161 strong function signatures data components, parameters, passing, 154 Intellisense, 154 versus variant arrays, 155

style sheets (XML), 136-138 style sheets (XSL) tags, 301 templates, 302-304 subscribers, events creating (New Subscription Wizard), 235-236 enabling, 236 filtering, 238 implementing, 234-236 loosely coupled events (LCE), 232 system application roles (Component Services) Administrator, 40 Any Application, 40 QC Trusted User, 40 Reader, 40 Server Applications, 40 system crashes, recovery from (CRM), 249 system modeling databases entities, 66 relationships, 66 logical model goals, 67 patterns, 67 UML, 68 three-tier diagram, 69 PubsOnLine application, 408-415 system-wide error logs, creating (CRM), 249-252

T
tags HTA attributes, 325-326 XML syntax, 301 XSL choose, 305-306 element, 306 for-each, 305 if, 305 style sheets, 301-304 value-of, 305 TaskItem object (Outlook 2000), 345 templates transactional Web pages (IIS 5), 291-292 XSL style sheets, 302-304 test environments, establishing, 24-26 testing applications Component Load Balancing (CLB), 369 Network Load Balancing (NLB), 367-368 Web Application Stress tool (WAS), 364-367 thread-neutral apartments (TNA), 16-17, 85 threads multi-threaded apartment (MTA), 16-17 single-threaded apartment (STA), 16-17 thread-neutral apartment (TNA), 16-17 three-tier applications classes business services, 69 data services, 69 user services, 69

474

three-tier applications

creating (Exercise 4.1), 105-109 data partitions, 123-125 payloads, 125-126 transports, 125-126 data transports delimited strings, 126-127 disconnected recordsets, 129-130 property bags, 131-134 variant arrays, 127-128 layers, separations, 21-23 OOP, 23 PubsOnLine application, 408-410 Add Book to Cart use case, 412-414 Checkout use case, 414-415 component definition, 415 Log In use case, 410-411 tickets (Kerberos protocol), 210 tiered architecture (Windows DNA), 10 tightly bound events, 232 Tools menu commands, Add Procedure, 50 transaction context, 185-187, 189 transaction processing (CRM Worker), 242 Transaction tab (Component Services component property), 43

transactional boundaries business services layer, 189-190 coarse data components, 186-189 design, 187-189 fine-grained components, 189-190 transactional components automatic transactions consistency bit, 192-198 done bit, 192-198 error handling, 195-198 mutually exclusive options, 184-185 Resource Dispensers, 185 Resource Managers, 185 voting process automatic, 190-195 manual, 190, 195 transactional Web pages building (Quick Check 11-2 exercise), 297-298 creating (IIS 5), 290-294 multi-page, creating (IIS 5), 292-294 transactions attributes (ACID), 182 building, 199-204 CRM flags, 244 isolation, 249 success/failure voting process, 245 distributed, two-phase commit, 183

monitoring (Component Service explorer), 198 QC client-side, 271 server-side, 272 rollbacks, 182 Transfer method, transaction example, 202-203 transforming data components (DNA Payload), 167-169 transports data sets in three-tier applications, 125-126 delimited strings, 126-127 disconnected recordsets, 129-130 advantages, 134 disadvantages, 134 property bags, 131-134 SOAP protocol, 141 Stream object (ADO), XML data, returning, 139-141 variant arrays, 127-128 XML, 134-138 troubleshooting collisions, 143-144 tuning Registry settings, session pooling 117-120 two-phase commit commit, 183 CRM, 242 distributed transactions, 183 prepare, 183 two-tier applications cursors, 19 maintenance difficulties, 20-21

Visual Basic

475

record-locking, 19 scalability issues, 20 site design disadvantages, 20 typical diagram, 19

U
UDA (Universal Data Access), 14 UML (Unified Modeling Language) Actor symbols, 59-60 logical model, 68 use case symbols, 59-60 Unified Modeling Language, see UML Universal Data Access (UDA), 14 Universal Data Link (UDL) files versus constructors, 238 unloading in-process components (IIS 5), 284 updating records, collision prevention, 142-143 use cases project design, 58-60 alternate path event flow, 64 alternate scenarios, 63 basic path event flow, 63 conditions, 62-63 documenting, 60-61 exception path event flow, 64 exception scenarios, 63 flow charts, 64

header sections, 61 perfect scenarios, 63 prototypes, 65 purpose statements, 62 rules, 62-63 PubsOnLine application, 393-394 Add Book to Cart, 397-399 Checkout, 401-402 Log In, 394-396 View Cart, 399-400 user services layer applications, deploying, 359, 363 three-tier applications, 21-23 users Active Directory, information tracking, 12 enterprise applications, scaling, 16 roles Administrator (Components Services), 40 Any Application (Components Services), 40 declarative security, 222 QC Trusted User (Components Services), 40 Reader (Components Services), 40 Server Applications (Components Services), 40

V
value-of tag (XSL), 305 variant arrays characteristics, 127-128 data components, data, sending, 155-158 Debug Assert( ) method, 156 disadvantages, 155 marshaling process, 127-128 returning, 127-128 versus strong function signatures, 155 versus XML, 158 VBControlExtender object, WithEvents keyword, 321-322 VBScript ASP pages, script classes, 294-296 Outlook 2000 object model, 340-341 Visual Basic applications, developmental evolution, 84 components creating (PubsOnLine.com Application), 425-428 debugging, 354-355 CReadData template (PubsOnLine.com Application), 428-433 CWriteData template (PubsOnLine.com Application), 433-436

476

Visual Basic

debugging binary compatability, 354-355 breakpoints, 354 conditional compilation, 355 events early bound, 232 tightly bound, 232 Outlook 2000 object model, 340-341 property bags, 131-134 PubsOnLine.com Application, 418 Visual InterDev, 26 debugging, access restrictions, 355 PubsOnLine.com Application, 418 Web site creation, 445-447 Visual Studio, 26 Installer, client software setup, 360-361 voting transactional components automatic, 190-195 manual, 190, 195 success/failure process (CRM), 245

W
Web Application Stress tool (WAS) application analysis, 363 downloading, 363 interface, 364

performance counters, 365-367 testing process, 364-367 Web browsers, Exchange 2000 Server Web stores access, 332-337 Web stores queries, 335-336 Web pages ASP scriptless processing (IIS 5), 290 corporate portals (Outlook 2000), 348-351 custom error messages, generating (IIS 5), 285-288 digital dashboards (Outlook 2000), 348-349 transactional building (Quick Check 11-2 exercise), 297-298 creating (IIS 5), 290-294 Web servers, HTA applications, deploying, 326 Web sites Active Directory, user personalization, 12 e-commerce applications, creating, 105-109 PubsOnLine.com Application, creating, 445-447 two-tier applications, maintenance difficulties, 20-21

Web stores (Exchange 2000 Server), 332-337 Win32, front-end applications, state/workflow layer, 312-313 Windows 2000 Active Directory, 24-25 group policies, 212 LDAP protocol, 12 Microsoft Installer (MSI), 211 security features, 210 single sign-ons (SSO), 211 user information, 212 Advanced Server, 24 Internet Information Server (IIS), 12, 25 Kerberos protocol authentication, 210 Microsoft Message Queue (MSMQ), 25 Network Load Balancing (NLB), 16 services Advanced Server, 11 Data Center Server, 11 Professional Workstation, 11 Standard Server, 11 SQL Server, 26 XML Document Object Model (DOM), 14 Windows Distributed interNet Application 2000, see Windows DNA Windows DNA (Windows Distributed interNet Application 2000), 10, 14

XSL

477

Windows NT, LAN Manager Security Support Provider 209 Windows Scripting Host, see WSH WithEvents keyword (MSMQEvent object), 261-262 write-ahead operations (CRM Worker), 244 writing batch files (WSH), 383-384 problem statements, project design, 54-55 Wscript object (WSH) methods 384 properties, 385 WSH (Windows Scripting Host), 383-384 application shutdowns (Quick Check exercise 15-3), 386-387 batch operation languages, 383-384 objects Shell, 385 WScript, 384-385

X-Y-Z
XML (eXtensible Markup Language), 14, 134, 300 COM+ objects, returning, 135-136 data components, parameters, passing, 158-161 delimited strings, selfdefined, 126

HTML pages, data transformation, 136-138 Internet Explorer output, 136 support, 14 parsers, 140 payloads, 158-161 returing from Stream Object (ADO), 139-141 streaming, 14 parameters, passing, 160-161 style sheets, 136-138 tags, syntax, 301 versus variant arrays, 158 XSL style sheets, associations, 300-301 XML Document Object Model (DOM), 14 XML2HTML method (Dataset object), 174-175 XSL (eXtensible Style Language), 136-138, 300 Online Shopping Cart cart database creation, 306-307 components creation, 307 Web site creation, 307-309 style sheets tags, 301 templates, 302-304 XML processing instructions, 300-301 tags choose, 305-306 element, 306 for-each, 305 if, 305 value-of, 305

XML data, associations, 300-301 XML transformation to HTML, 136-138

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 copyright 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 purpose. 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.)