Building Distributed Applications
Building Distributed Applications
MEDIA DEVELOPER
Warning and Disclaimer Dan Scherf
Every effort has been made to make this book as complete and as accurate as
INTERIOR DESIGNER
possible, but no warranty or fitness is implied. The information provided is on
Anne Jones
an “as is” basis. The author(s) and the publisher shall have neither liability nor
responsibility to any person or entity with respect to any loss or damages aris- COVER DESIGNER
ing from the information contained in this book or from the use of programs Aren Howell
accompanying it.
Contents at a Glance
Foreword x
Introduction 1
Index 705
Foreword
The shift to .NET technologies is underway, bringing with it exciting opportunities that only
distributed computing makes possible. This I know to be true, having experienced the awesome
power of .NET technologies at work each day where our award-winning internal systems run
on the .NET platform.
As Chief Technology Officer at Quilogy, a provider of business solutions through digital con-
sulting, advanced hosting, and technical education, I have worked closely with Dan Fox over
the past several years learning, experimenting with, and applying new Microsoft technologies
to our own organization. For only by testing and building proven solutions for ourselves can
we be sure to provide our customers with the best, most effective solutions. Our work over the
past year to incorporate .NET strategies has been especially rewarding.
Dan’s demonstrated mastery of .NET technologies at Quilogy as well as his previous profes-
sional experiences building large-scale systems for a major oil company, extensive knowledge
of database and object-oriented systems, as well as numerous Microsoft certifications make
him uniquely qualified to write this book. Additionally, this year marks the 10th anniversary of
Visual Basic, which makes this book’s publication particularly meaningful. As we have found
for ourselves, the best way for professional VB developers to enter into the .NET sphere is
through Visual Basic .NET.
As the leading language used by corporate developers to build solutions, VB with its new .NET
qualities now can address even more of the needs and concerns of business developers, which
makes understanding it at this time so crucial. Part of the great news about .NET is that you
can move into it and still leverage your existing skills because of its multilanguage support. As
the book shows, there are some concepts and techniques you’ll need to learn, but they’ll build
on those you already have, so you can start to take advantage of all the new features and capa-
bilities that .NET has to offer.
Rather than restating Microsoft’s documentation, Dan explains the course of an application’s
development and offers wide-ranging insight as he delves into the whys, such as why VB .NET
is important, and the hows, such as how VB .NET fits into the general scheme. Additionally,
numerous code examples clearly illustrate key points and complement the book’s easy readabil-
ity. Dan is a sought-after instructor and speaker at such major events as TechEd and Developer
Days. He is also a regular contributor to several print and online magazines including Visual
Basic Programmers Journal, SQL Server Magazine, InformIT, and Advisor journals. His exem-
plary teaching methods, engaging speaking voice, and comprehensive knowledge shine through
in this book.
Currently as Technical Director, Dan is charged with helping me select technologies, set appli-
cation architecture, identify successful design patterns, and educate staff on emerging technolo-
gies. Since taking on this important position in the company, he has been instrumental in the
development of Quilogy’s breakthrough system for building portal solutions called Quilogy
Accelerator (QA). Using the code to Quilogy’s own intranet as a .NET accelerator, QA facili-
tates the process of creating portal and intranet solutions faster and less expensively than either
buying or building from scratch.
As we have found with QA and you will find as you apply .NET strategies to your own busi-
ness practices, .NET is changing the face of technological business solutions in extraordinarily
exciting new directions.
Alan Groh
CTO Quilogy
About the Author
Dan Fox is Technical Director for Quilogy in Overland Park, Kansas. Quilogy (www.quilogy.com)
is a leading Microsoft Gold Certified Partner and Solution Provider with more than 450 con-
sultants nationwide in 16 cities. Quilogy provides digital consulting and technical education
services to a wide range of clients and specializes in building solutions on the Microsoft plat-
form. As a Certified Technical Education Center, Quilogy teaches the range of Microsoft
Official Curriculum (MOC) courses and specializes in building solutions and teaching courses
using both .NET development and .NET Enterprise Servers.
Dan is a Microsoft Certified Solutions Developer, Systems Engineer, and Trainer who has been
a consultant, instructor, and managing consultant on a variety of projects. In his role as a
Technical Director, Dan provides technical guidance to Quilogy’s consultants and customers.
Before joining Quilogy in 1995, Dan worked for Chevron in Houston, Texas, and the National
Association of Insurance Commissioners in Kansas City, Missouri. Dan earned his B.S. in
Computer Science from Iowa State University in 1991.
Dan has been a frequent contributor to the Visual Basic Programmer’s Journal and has written
numerous articles for SQL Server magazine, Advisor journals, and InformIT.com. He authored
the book Pure Visual Basic from Sams and coauthored a book on the Visual Basic 6 Distributed
Exam (70-175) for Certification Insider Press. He has spoken at TechEd and several Developer
Days conferences and Microsoft events.
Dan lives in Shawnee, Kansas, with his lovely wife, Beth, and two young daughters, Laura and
Anna. Besides earning the nickname “Dan.NET” from his family, Dan spends his time reading,
enjoying movies, and as always, rooting for the Cubs.
Acknowledgments
First, I’d to thank the Senior Acquisitions Editor on this project at Sams, Sondra Scott. From
our initial contact, she has been an encouragement and a great person to work with. She made
sure that each step in the process went smoothly and provided excellent feedback early in the
process in the form of reviews. In addition, I’d like to thank Shannon Leuma, the Development
Editor, who was ever vigilant to keep me on schedule, make sure that the content was well
organized, and made many suggestions that served to make this a better book.
Of course, the two key elements of any technical book such as this, the actual written word and
the code, were greatly improved by the copyediting skills of Mike Henry and Geneil Breeze,
and the technical reviews of Phil Syme, Dan Suceava, and Eric Wilson. The five of them made
sure that the book was readable and contained accurate information, something that was diffi-
cult given the fact that the reviewers had to work with multiple beta versions of the product for
most of the development cycle.
As you can tell from the cover and forward, this book was a team effort by Quilogy, the com-
pany for which I work. President and CEO Randy Schilling and Chief Technology Officer
Alan Groh’s encouragement and investment in the project was instrumental to making it a suc-
cess. Because the book was developed so early in the product life cycle, their willingness to
give me the resources to develop a book of this scope, including both the time and travel to
Redmond, contributed greatly to the quality of the final result. Throughout the process, Quilogy
consultants and instructors reviewed the content and provided helpful advice and suggestions.
To all these talented people, I’m certainly indebted, particularly, Tim Vanover, Dave Wanta,
Jason Wisener, Sue Van Gels, Adrian Anttila, and Cathey Barrett.
In addition, the scope and purpose of the book was shaped and honed through excellent reviews
by Ari Bixhorn, VB Product Manager at Microsoft; Steve Hoag, Senior Technical Writer for
VB User Education at Microsoft; Kyle Lutes, Assistant Professor at the Computer Technology
Department of Purdue University; Richard Nelson, Senior Software Architect at Intuitive
Manufacturing Systems; Lars Powers, Vice President/Solution Development at Acclarant, Inc.;
Mike Snell, Chief Software Architect at Acclarant, Inc.; and Larry Wall, Team Leader Microsoft
Group at Synapse Technology. Thanks to all of you for your help.
And so, as is true of any book, this one was truly a team effort. That being said, any errors are
only mine, so feel free to e-mail me at [email protected] with corrections and suggestions.
Finally and most importantly, I couldn’t have embarked on this project without the loving sup-
port of my wife, Beth, and daughters, Laura and Anna. Beth’s continuous encouragement and
patience during this project made it much easier to accomplish, and my girls as always pro-
vided the balance that keeps my technological pursuits in perspective.
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 Publishing, I welcome your comments. You can e-mail
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.
E-mail: [email protected]
uses SQL Server 2000 on the back end, so although ADO.NET supports accessing other
providers, the examples in this section and throughout the book will focus on SQL Server.
Chapter 8, “Building Components,” discusses how components are built in VB .NET. The
chapter also looks at legacy DLLs to ensure that your existing code can be used in .NET.
Finally, a discussion on how components in VB .NET applications can be shared with .NET
Remoting is presented, which, like its precursor DCOM, often comes in handy when the sub-
systems in a distributed application need to communicate across process and machine bound-
aries. Chapter 9, “Accessing Component Services,” logically follows by discussing how
business and data access logic in VB .NET components can be integrated with Windows 2000
Component Services. This allows your VB .NET components to take advantage of the object
pooling, just-in-time activation, transactional control, and other features VB developers rou-
tinely implement in distributed applications. In addition, this chapter shows how components
built in VB .NET can interoperate with classic COM components.
Part II is rounded out with Chapter 10, “Building Web Forms” and Chapter 11, “Building Web
Services,” which cover the aspects of the presentation services layer necessary to build a Web-
based application. In large part, Chapter 10 covers the architecture and features of ASP.NET
and how they differ from ASP and then discusses in detail the Web Forms programming model
using the UI of the Quilogy sample application for illustration. Chapter 11 introduces a second
type of interface that VB .NET can produce by discussing Web Services. Because Web
Services are a new concept to many developers, this chapter provides a foundation by explor-
ing the underlying technologies involved and how they are implemented in VB .NET.
can be thought of as a tool used to integrate the prebuilt components of the Services Framework
into a specific solution. Thinking of VB .NET this way should come as no surprise to existing
VB developers because the strength of previous versions of VB also was integrating prebuilt
and custom components.
The approach I recommend when reading the book is to read the entire section, tracking with
the code listings and snippets, and then perusing the online documentation or other sources for
any additional information before developing your own samples in your own problem domain
using the listings as a starting point. To help you in this endeavor, as mentioned earlier, the
code listings, along with the complete Quilogy sample application discussed in Chapters 7
through 11, can be found on the Sams Web site at www.samspublishing.com. To remind you of
this as you read, each chapter introduction includes the following note:
NOTE
All code listings and supplemental material for this chapter can be found on the
book’s Web site at www.samspublishing.com.
In addition, when using the listings, it should be noted that because in VB .NET the act of ref-
erencing external libraries usually entails placing an Imports statement at the beginning of
your code file, many of the code listings and examples contain shaded Imports statements at
the beginning. These are shaded because they wouldn’t appear in actual code in that location
but are required to produce the code found in the listing or example.
This book intentionally is heavy on code listings and short on figures. I believe that developers
can learn more quickly by viewing the code of others rather than through a tutorial or a simple
discussion. I tried to restrict the use of figures to those required to place a concept in context
or, for example, to give you an idea of where in the VS .NET UI to look for a particular fea-
ture. The screen shots should not be used as a tutorial, and as you work with VS .NET, the par-
ticulars of your solution will mean that the screens you see might differ.
I’ve also focused primarily on how you implement features using code rather than the graphi-
cal designers and wizards included in VS .NET. This too is intentional because I believe that to
develop a firm foundation you need to understand what’s happening at the code level and by
nature, graphical interactions and wizards don’t translate well to this medium.
COM components to house their data access and business logic and employing Microsoft
Transaction Server or Component Services. They are also versed in ADO and ASP develop-
ment and are just beginning to use XML. For these developers, the primary challenge when
moving to VB .NET is the object-oriented nature of the Services Framework and the additional
language syntax used to implement these features. As such, Chapters 3 and 4 will be especially
useful.
The secondary audience is the ASP developer who typically has less formal training and spe-
cializes in Web development. For these developers, the challenge is to move from building
two-tiered Web applications to a multitiered architecture, as described in Chapter 7. In addi-
tion, the richness of the VB .NET language, as opposed to VBScript or JScript, will require an
adjustment.
Finally, the many classes in the Services Framework that allow you to easily use system ser-
vices will open up a new world of possibilities. I’ve tried to highlight the portions of the
Services Framework (especially in Part III) that will be the most useful.
I wrote this book because I think that the underlying technology of the platform and the direc-
tion Microsoft has chosen with VB .NET make it ideally suited to developing distributed appli-
cations. However, the paradigm shift associated with the platform and the sheer size of the
product will make it difficult for some VB developers to get a handle on how to use VB .NET.
In the end, this book provides a bit of a roadmap and a survey of VB .NET and the Services
Framework and how it can be used to build distributed applications.
So what are you waiting for? Let’s get started by exploring the foundation of VB .NET: the
Microsoft .NET architecture.
Dan Fox
Shawnee, Kansas
August 2001
PART
.NET Concepts
I
IN THIS PART
1 The Microsoft .NET Architecture 9
1
Architecture
IN THIS CHAPTER
• A New Platform 11
As you are no doubt already aware, Visual Basic .NET (VB .NET) is far more than simply a
new release of Visual Basic. VB .NET is actually a piece in the larger puzzle of Microsoft’s
.NET architecture. This architecture encompasses not only a new release of Visual Studio
(Visual Studio .NET), which includes a suite of languages and a common platform on which
all the Visual Studio languages run referred to as the .NET Framework, but also new releases
of server products such as SQL Server 2000, BizTalk Server 2000, and Application Center
Server 2000, collectively referred to as .NET Enterprise Servers.
A Storm Coming?
In addition to the .NET development and server story, Microsoft has disclosed prelimi-
nary plans for building and hosting a set of Web-based services under the name .NET
My Services (formerly codenamed Hailstorm). Briefly, these services will be built using
technology in the .NET Framework and will allow users the ability to share and con-
sume personal information anywhere on any device. The core of the initiative is to
integrate disparate silos of information such as tasks, contacts, inbox, schedule, notifi-
cations, and favorites, among others, into a single secure Web-based information
store accessible via standard Internet protocols.
Currently, Passport, Microsoft’s authentication service, is the only publicly available
piece of this vision that is referred to both as Building Block Services and Foundation
Services. Passport integration in ASP.NET will be discussed in Chapter 10, “Building
Web Forms” while more information on .NET My Services can be found at
http://www.microsoft.com/myservices/default.asp.
Together, all these new tools are designed to help developers build modern, robust, distributed
applications. To help you understand how VB .NET fits into the architecture, this chapter will
discuss the platform and its implications for VB developers. Although this is a large chapter
with a lot of technical material, the differences in the fundamental architecture between previ-
ous versions of VB and VB .NET are significant. So significant, in fact, that you need to
immediately get a baseline for how these changes have been implemented and what they mean
to the larger picture of the .NET Framework and Visual Studio .NET.
NOTE
All code listings and supplemental material for this chapter can be found on the
book’s Web site at samspublishing.com.
The Microsoft .NET Architecture
11
CHAPTER 1
A New Platform 1
THE MICROSOFT
For corporate developers, application development has gone through several major shifts in the
ARCHITECTURE
last decade. As we started the 1990s, we were already immersed in the shift from developing
.NET
character-based monolithic mainframe applications to two-tier client/server applications on
PC-based hardware and operating systems utilizing ODBC-compliant relational databases and
graphical user interfaces (GUIs). At nearly the same time, we began to see the adoption of
object-oriented programming (OOP) concepts such as encapsulation, inheritance, polymor-
phism, and reusable components into development tools such as PowerBuilder and Visual
Basic. With a subsequent move to distributed computing relying on n-tier architectures and
component-based programming, by early 1997, many of these tools and technologies were rel-
atively mature, widely distributed, and entrenched in the corporate developer community.
From the perspective of a corporate developer utilizing Microsoft products, this produced an
architecture in which a Visual Studio client application written in VB or Microsoft Foundation
Classes (MFC) communicated with COM components running in Microsoft Transaction Server
(MTS) using the DCOM protocol. The components themselves accessed a relational database
such as SQL Server or Oracle using an ODBC driver or, later, an OLEDB provider. By utiliz-
ing the object context, MTS gave developers the ability to handle transactions across these het-
erogeneous databases using XA (a subset of services from the X/Open Distributed Transaction
Processing (DTP)) and centralized object destruction and creation.
Of course, the largest change had reached critical mass by 1997 with the widespread adoption
of the Internet, HTML, and now XML. Although Microsoft released a new development tool,
Visual InterDev (VID), and a programming model for Web development, Active Server Pages
(ASP), both of these were largely additions to the existing architecture that provided integra-
tion with existing components and relational databases, but did not alter the way development
was done in the core Visual Studio languages Visual Basic and Visual C++. In addition, the
programming model and visual design tools provided in VID and ASP were not nearly as
robust as those in the more mature products. Attempts to integrate Web programming into VB,
such as the inclusion of ActiveX documents, DHTML applications, and Web classes, only
illustrated the point that at their core, the flagship development tools were ill-suited for life in a
Web world. One of the main reasons for this is that the tools relied on technology—such as the
Win32 API, COM, and DCOM—that was developed in the early 1990s when desktop comput-
ing was central and when persistently connected clients in an insulated LAN environment were
the norm.
Developing applications for which the Internet is the platform requires a different mindset—a
mindset that moves from thinking of writing software for only internal consumption to one in
which all users of the Internet are your potential customers. And this requires different technol-
ogy that is up to the task of incorporating support for the loosely coupled nature of clients and
.NET Concepts
12
PART I
servers, a new security model, and the integration of industry standard HTTP and XML as
ubiquitous protocols. I don’t know about you, but if all this could be packaged within a modern
object-oriented framework that provides maximum reusability and developer productivity, it
sounds like a platform I’d like to use.
And so, at its core, the .NET Framework and Visual Studio .NET (which I’ll refer to together
as simply .NET) are tools designed to take advantage of the Internet as the major platform for
application development. At the highest level, the goals for the initial release were to produce a
development environment:
• Where the Internet and Internet standards are second nature
• Where distributed Web applications are easy to build
• That combines the power of object-oriented programming and relieves the burdens of
complicated versioning and deployment
In the remainder of this section and chapter, I’ll talk specifically about what .NET is and dis-
cover how Visual Basic .NET fits in.
important than being able to run the same binary on various platforms. In addition, the amount 1
of integration possible in .NET far exceeds that provided by COM and extends all the way to
THE MICROSOFT
ARCHITECTURE
cross-language inheritance.
.NET
In any case, Microsoft’s vision for platform independence relies on industry standards such as
Simple Object Access Protocol (SOAP), an XML-based protocol, to make cross-platform calls
and interact with services exposed over the Web (also known as XML Web Services).
Companies throughout the industry from IBM to Sun are supporting the SOAP standard now
in the hands of the W3C (http://www.w3.org/TR/SOAP/), and so its inclusion in .NET moves
us forward to the time when applications built on differing platforms will be able to communi-
cate seamlessly.
NOTE
For a look at a variety of Web Services built on various platforms, see
www.xmethods.net.
On the other side of the fence, .NET is a new platform for developing distributed Web applica-
tions. .NET mainstreams the concept of Web Services as programmable application compo-
nents accessible via standard Web protocols. The .NET Framework includes hundreds of
prebuilt classes that encapsulate these Web standards and protocols to provide a great founda-
tion for building both interactive Web applications and Web Services, as I’ll discuss in
Chapters 10, “Building Web Forms,” and 11, “Building Web Services.”
.NET also provides a new model for building and sharing components. As you’re probably
aware, the reliance of classic COM components on registry entries, Globally Unique
Identifiers (GUIDs), v-tables, and IUnknown makes distributing and invoking those compo-
nents across the network using DCOM sometimes tricky. In .NET, all those concepts go away
and are replaced by a simpler mechanism that allows remoting of components across the net-
work, easy deployment, and side-by-side versioning of components on the same machine. You
will explore many of these concepts in Chapters 5, “Packaging, Deployment, and Security,”
and 8, “Building Components.”
Finally, .NET is a Rapid Application Development (RAD) tool for distributed applications.
The inclusion of the Server Explorer window in the VS. NET IDE (covered in Chapter 2, “The
Development Environment”), the .NET Framework classes for manipulating data through
ADO.NET (covered in Chapter 7, “Accessing Data with ADO.NET”), and integrating with
both low-level system services such as threading (covered in Chapter 12, “Accessing System
Services”) and high-level services such as messaging and Active Directory (covered in Chapter
14, “Integrating with the Enterprise”) make it a high-productivity environment.
.NET Concepts
14
PART I
NOTE
The phrase in theory in the previous paragraph refers to the fact that compilers, as
well as the .NET Framework, play a role in performance. Even if the VB .NET language
contains syntactical equivalents for all VC# constructs, the VB .NET compiler would
still have to produce intermediate language code (as discussed later) identical to that
produced by the VC# compiler in order for two applications to perform identically.
This is unlikely, and so in certain circumstances a language built on the .NET
Framework might outperform another language when executing similar operations.
However, these small differences will also tend to even out in the scope of an entire
application.
In the initial release of VS .NET, VC++ will be the only language through which you
can create code that does not use the CLR at all. VC# will allow you to write code
blocks that do not use the CLR and so in both cases, when using these features, all
bets on performance are off.
Entire books have been written on how to extend VB to implement specific features (and break
through the “glass ceiling”) of the Win32 API, such as threading, callbacks, and writing NT
services. (I know because I’ve written one of them.) However, with VB .NET, all these features
are transparent and accessible through a set of class libraries that ship with VS .NET, called the
.NET Framework classes or the Services Framework. Using the Services Framework in your
applications allows VB .NET to support the RAD model that VB developers have come to
expect.
The Microsoft .NET Architecture
15
CHAPTER 1
NOTE 1
THE MICROSOFT
ARCHITECTURE
Throughout this book I’ll use the term Services Framework to refer to the entire col-
.NET
lection of over a thousand classes that ship with Visual Studio .NET, both those that
implement support for the various programming models such as Web Forms and Web
Services, and the lower-level classes that implement network communication, IO,
threading, and so on. Some authors will refer to the entire collection as simply the
.NET Framework, .NET Frameworks, or Base Class Libraries (BCL). Although I seldom
use the term, I reserve BCL for the lower-level classes upon which the higher-level
programming models are built.
The second point to consider is that VB .NET not only encompasses the functionality of previ-
ous versions of VB to create form-based applications and components, it also can be used to
create Web applications using a robust event-driven programming model. In other words, the
functionality of the forms package and ASP have been abstracted into application program-
ming models and exposed to all the .NET programming languages through reusable framework
classes.
NOTE
As a result of the inclusion of the Web-based programming into the Services
Framework, developers who in the past used Visual InterDev as their primary tool will
likely be migrating to VB .NET. For developers, moving from a language such as
VBScript, which did not support types other than Variant and lacked support for
more sophisticated features like classes and events, to the robust .NET languages
might at first seem daunting. For those developers I say, bear with me. Much of the
information in this chapter is crucial for getting the big picture. That being said,
those developers will find more of the information for which they are looking, and
can move through the book using a faster track, by concentrating on Chapters 2, 3, 4,
7, 10, and 11.
In addition, many of the intrinsic functions and statements have been abstracted into the
Services Framework and the CLR, the result being that VB .NET actually contains fewer
keywords than previous versions. A picture of how these parts fit together can be seen in
Figure 1.1.
.NET Concepts
16
PART I
NOTE
VB .NET is a Common Language Specification (CLS)–compliant language and so it can
take advantage of the CLR. There is a more complete discussion of the CLS later in
this chapter.
Services Framework
Microsoft .NET Framework <
Common Language Runtime
SOAP
HTTP
Internet Standards <
TCP/IP
FIGURE 1.1
The .NET architecture. Much of the functionality of previous versions of VB has been abstracted into the application
programming models and Services Framework.
Taken together, you can infer that VB .NET is different from previous versions of VB because
it is now only one of many languages that take advantage of the services provided by the .NET
Framework. This is great for VB developers because they can now access all the features .NET
provides without paying the price of increased complexity, kludgy workarounds, and degraded
performance.
In the remainder of this chapter, I’ll drill down on the foundation of Figure 1.1 and discuss the
key concepts behind the CLR and the Services Framework.
NOTE 1
THE MICROSOFT
ARCHITECTURE
See Jeffery Richter’s series of articles on the MSDN Web site (msdn.microsoft.com) for
.NET
more details on the CLR.
As was true with VB 6.0 and COM, developers creating distributed applications could get
by with developing their applications without any appreciation for the internals of COM.
However, extending that knowledge just a little bit allows you to create applications that take
full advantage of what the CLR provides.
NOTE
COM does support the notion of interface inheritance so that one object can imple-
ment another’s interfaces (which defines the required method and property signa-
tures including the method names, arguments, and return values, if any). This allows
you to write polymorphic code and could also be done in VB 6.0 (see Chapter 15 of
my book, Pure Visual Basic, Sams Publishing, August 1999, for a more in-depth discus-
sion). However, this technique does not allow the actual code inside the object to be
reused. Implementation inheritance means that one object can be derived from
another and that when the derived object is executed, the code from the parent will
also run if desired. This leads to greater code reuse, although there are pitfalls as
well. We’ll look more closely at these features as they’ve been added to VB .NET in
Chapter 4, “Object-Oriented Features.”
The CLR provides the common substrate within which all the software runs so that objects can
directly interact, and so that all the plumbing code is eliminated from both the components
themselves and the operating system. For example, in the COM world, components were
responsible for the in-memory layout of their objects into v-table structures so that the appro-
priate methods could be located at runtime. Now, however, this responsibility has been relieved
from the components and is handled by the CLR.
Because all VB .NET code is run by the CLR, it can provide services like those listed here:
• Different compilation models—As I’ll discuss shortly, the abstraction of the CLR from
the development languages allows the runtime to determine when an application is com-
piled.
• Automatic lifetime management—Because all objects—and everything is ultimately an
object in .NET—are managed by the CLR, it can monitor when those objects are created
and used, and when they are no longer needed. As a result, it will use a garbage collec-
tion (GC) algorithm to free resources as necessary. This means that you can no longer
have stray pointers and that circular references will be resolved. In fact, you are no
longer responsible for freeing resources (setting an object to Nothing, for example) at all.
This is great news, but it changes the way you will design your code, for example,
because Terminate events are no longer supported. I’ll cover this topic in more detail
both in this chapter and in Chapter 3, “VB .NET Language Features.”
• Code correctness and type-safety—VB developers have always taken for granted that
in many cases they could assign a variable of one type to another and VB would auto-
matically convert it for them. By default, however, the CLR strictly enforces type safety
so that developers can’t make arbitrary references to memory locations and make unsafe
The Microsoft .NET Architecture
19
CHAPTER 1
casts—things that VB developers typically don’t care about, but that happen frequently 1
in VC++ and are exploited by hackers. What it means to VB .NET developers is that
THE MICROSOFT
ARCHITECTURE
there is a new default behavior and more levels of type safety that can be used. I’ll cover
this in detail in Chapter 3.
.NET
• Simplified deployment—Because the CLR eliminates the plumbing required for com-
ponents to communicate, it also reduces the installation and deployment burden for
developers. By eliminating registration (for the most part, as you’ll see in Chapter 5.)
and allowing features such as side-by-side execution both on the same machine and even
within the same process, some .NET applications can be deployed simply by copying
directories (referred to as XCOPY deployment).
• Evidence-based security—This new platform also requires a new security model. In the
past, security models typically relied on the credentials of the user running the code.
However, in distributed applications where code can be downloaded from the Internet
and executed, the code itself needs to be trusted. The .NET security model is not simply
a rehashing of the Microsoft Authenticode technology used for signing and encrypting
ActiveX controls; it is a new model based on evidence provided by both the code as well
as the user (through operating system accounts or roles) and is policy-based. In addition,
the security model can be accessed both declaratively and imperatively inside your code.
I will discuss this in more detail in Chapter 5.
• Common exception handling—As mentioned previously, the varying programming
models used by corporate developers all handle errors in different ways. COM uses
HRESULTs, the Win32 API uses function return values with a second call to retrieve the
error, ASP uses inline error handling, and VB uses error trapping within a module. The
CLR includes structured exception handling, which allows isolation of the error code and
works well across language boundaries. I’ll discuss how VB .NET implements this fea-
ture in Chapter 6, “Error Handling and Debugging.”
These features of the CLR allow languages to work together and leverage common tools such
as the debugger and profiler so that cross-language and even cross-machine debugging (cov-
ered in Chapter 6) are simplified. This results in a greater freedom to use the language of your
choice without sacrifice. This is, once again, good news for VB .NET developers.
And finally, as implied earlier and discussed in the following sections, the all-encompassing
nature of the CLR gives it the nature of a Hardware Abstraction Layer (HAL) and makes it
possible to write code that might not require recompilation as you move it to a new platform.
Initially, Microsoft is planning to port the CLR to its family of operating systems including
Windows 98, Windows Me, Windows NT 4.0, Windows 2000, Windows XP, 64-bit Windows,
and even Windows CE in a package called the .NET Compact Framework. In the future, other
non-Microsoft operating systems might also be included.
.NET Concepts
20
PART I
NOTE
As mentioned previously, only VC++ can produce unmanaged code. The default mode
for VC++ is to create unmanaged code, and so the product is referred to as “Visual
C++ with managed extensions.” However, VC# will also allow you to write unman-
aged code within a method by using the unsafe modifier. As a result, a VC# devel-
oper can use pointers and override the GC algorithm in certain cases to keep it from
freeing resources using a technique called pinning. As implied by its name, the
unsafe modifier can allow developers to override the features of the CLR noted in
the “Automatic lifetime management” bullet point earlier and therefore create stray
pointers and unresolved circular references. Note, however, that this unmanaged
code will run only if the code is trusted by the CLR security model.
VB .NET produces only managed code and so must use the interoperability features of .NET
(referred to simply as “interop”) to access any form of unmanaged code. We’ll take a look at
how this is accomplished in Chapter 9, “Accessing Component Services.”
One of the ramifications of this for VB .NET developers is that upgrading VB 6.0 projects to
VB .NET (covered in Chapter 3) means that the interop services will be relied upon heavily,
which adds a layer of complexity and slows performance. For these and other reasons, VB
.NET developers will need to be very careful when deciding what and when to upgrade.
The Microsoft .NET Architecture
21
CHAPTER 1
Death of COM?
1
THE MICROSOFT
ARCHITECTURE
With all these changes, what does this mean for COM? Well, the good news is that
because VB hid many of the complexities of COM from developers, changing the
.NET
infrastructure should not inconvenience most developers. In addition, doing away
with the headaches of GUIDs and the registry, the single-version-per-machine scheme
that it implied, as well as dealing with compatibility settings, are all a good thing. Is
COM dead? Yes, in terms of its infrastructure.
However, many corporate VB developers have a good understanding of COM and
take advantage of interface-based programming in their designs. These developers
can still use the same techniques in their designs, while they can also augment them
with implementation inheritance. Is COM dead? No, in terms of the concept of shar-
ing and reusing code.
In any case, many of us will have to coexist in both worlds for some time to come. For
example, one of the most common scenarios will be that newly developed managed
code (perhaps a new ASP.NET UI or Web Service) will need to call previously deployed
COM+ components written in VB 6.0. For this to work, VB .NET developers will need
to be aware of both the old and new worlds and how they interoperate (as I’ll discuss
in Chapter 9). In fact, it might be argued that some new VB .NET developers will need
a short course on classic COM to implement scenarios like the one mentioned.
NOTE
Strictly speaking, the CLS binds vendors to rules only for types that are made public
and accessible outside a particular assembly. Assemblies will be covered in more detail
at the end of this chapter.
.NET Concepts
22
PART I
In fact, the CLS dictates a subset of what the CLR provides for languages to be compatible.
Individual vendors can then implement more of the functionality if they desire. The CLS
defines three levels for compatibility:
• consumers—Languages that use the CLR but do not extend it
• extenders—Languages that use the CLR and extend it by adding additional data types
• frameworks—Languages that implement libraries used by a wide range of programming
languages and tools
As of this time, many vendors have indicated their willingness to create compilers for lan-
guages such as Pascal, Smalltalk, LISP, FORTRAN, Perl, and over 20 others. In fact, Microsoft
has even produced a version of Java (J# .NET) that targets the CLR as a part of its JUMP (Java
User Migration Path) program.
To assist in this effort, Microsoft and Hewlett Packard jointly submitted the CLS, CLR
(referred to as the Common Language Infrastructure), and the C# language specification to the
international industry standards body ECMA. See msdn.microsoft.com/net/ecma and
www.ecma.ch for more details.
NOTE
Obviously, this book is geared towards existing VB and ASP developers, and as such, I
am definitely of the opinion that these developers will be much more productive
much sooner using VB .NET than VC# due to the syntax similarities. In addition, VB
.NET preserves much of what was good about BASIC to begin with, namely a more
readable and hence understandable syntax. VC# was designed with C++ and Java
developers in mind and so will be the natural path to .NET for those developers. That
being said, VC# is in many respects more like VB .NET than C++, and so many VB
developers will have no trouble reading and understanding the syntax.
CLR Internals
To help you get a feel for how the CLR works, I’ll use an inside-out approach by first dis-
cussing what happens on a binary level and then moving up to a single application level, cross-
application level, and finally to the cross-machine and deployment level. I’ll begin the
discussion by focusing on how code is compiled and executed for the CLR.
MSIL
As with any executable today, the code you write in VB .NET eventually must execute as
native CPU instructions for the processor on which the code will be run. However, although
unmanaged compilers create these native CPU instructions directly, and interpreters such as
The Microsoft .NET Architecture
23
CHAPTER 1
ASP create instructions on the fly that map to CPU instructions, the managed compilers written 1
for the CLR, which include VB .NET, create a higher level, machine-independent set of
THE MICROSOFT
ARCHITECTURE
instructions referred to as Microsoft Intermediate Language (MSIL). The MSIL instructions
are then stored in a portable executable (PE) file with a .DLL or .EXE extension based on the
.NET
Microsoft Portable Executable format, which itself extends the Common Object File Format
(COFF) commonly used for executable content. These files are referred to as modules in .NET
(not to be confused with VB modules as discussed in Chapter 2). MSIL is eventually loaded by
the CLR and compiled to native instructions and executed.
To view the MSIL created by the VB .NET compiler, you can use the IL Disassembler utility
(ILDasm.exe) that ships with .NET. This graphical utility lets you view each method in your
program, along with its associated MSIL, by double-clicking on the method. Figure 1.2 shows
ILDasm opened up on a method called AddOrder in a class called Orders.
FIGURE 1.2
The IL Disassembler. This graphical utility lets you view the MSIL created for your VB .NET code. Note that the
instructions begin with IL_0000 in the foreground window.
This basic architecture and its implications should be familiar to VB developers. First, it means
that VB. NET binaries are not native code but a form of intermediate code as was true for most
of VB’s history. The big difference is that MSIL is a much lower level set of instructions than
the interpreted code produced in previous versions of VB. Although you might be thinking that
.NET Concepts
24
PART I
the fight for adding native compilation to VB was in vain and that this is a giant step back-
wards in terms of performance, there are benefits to using this approach, as will be discussed
later in this chapter. Second, it means that the .NET Framework must be installed on each
machine that executes VB .NET code. Yes, a runtime distribution is required for operating sys-
tems on which the runtime is not preinstalled (which is all of them at this point, even the newly
released Windows XP).
On the other hand, the use of MSIL is what makes it possible for VB .NET developers to take
advantage of all the services of the CLR discussed previously, such as garbage collection, type
safety, structured exception handling, security, integrated cross-language development, and
cross-language debugging. In addition, using MSIL will enable VB .NET code to run without
recompilation on new platforms, such as 64-bit Windows, by providing a hardware abstraction
layer.
At this time, operating systems don’t know how to begin executing programs written in MSIL,
so each managed executable contains an unmanaged entry point that the operating system’s
loader calls. This small stub simply jumps to the _CorExeMain function in the CLR engine
contained in MSCorEE.dll. After the CLR has been initialized, this function continues execu-
tion of the MSIL instructions from within the managed code. This implies that each process
loads its own copy of the CLR and that only one copy of the CLR is loaded per process. The
bulk of the core services in the CLR, such as the base classes for the Common Type System
discussed later, are contained in the MSCorLib.dll, which each managed binary also references.
JIT Compilation
Perhaps the biggest issue and perceived drawback to using MSIL and managed code is perfor-
mance. Obviously, adding another layer of abstraction also adds a performance hit as the MSIL
is compiled to native code. Fortunately, .NET uses some optimization techniques to try and off-
set this potential problem.
CAUTION
Another drawback is that in its current form, MSIL can be disassembled as shown in
Figure 1.2. This allows “reverse-engineers” to study the instructions for your source
code and duplicate it, thereby risking intellectual property. However, it should be
noted that any code (natively compiled or not) is in danger of reverse engineering if
the binary is accessible.
The Microsoft .NET Architecture
25
CHAPTER 1
By default, the CLR uses just-in-time (JIT) compilation at runtime to compile the MSIL. It 1
does this as opposed to compiling the entire application at load time so that the initialization
THE MICROSOFT
ARCHITECTURE
time is reduced, and because applications typically do not end up calling all their code. The
component of the CLR that performs this run-time compilation is often referred to as the JITer.
.NET
Note that the JITer and the CLR communicate via a standard interface so that JITers can be
produced by other vendors for specific platforms.
For example, when a managed application is executed, it is loaded by the CLR using its class
loader (technically a part of the Virtual Execution System or VES), which has the responsibil-
ity for first allocating memory for the code to be loaded, resolving access to other managed
code, and conducting basic consistency checks. When these checks are complete, the class
loader creates a stub for each method implementation that is loaded. As the methods are actu-
ally called in the course of program execution, the JITer is used to compile the MSIL into
native code that then replaces the stub. On subsequent invocations of the method, the native
code will run without intervention by the JITer.
In addition, the JITer also supports a code verification stage that might take place during com-
pilation. This algorithm uses input from the class loader and the CLR base class library to
make certain that the code about to run is type-safe. This means that the method implements
the correct signatures and that any incoming values to the method have the correct signature. If
the code passes the type-safe verification, it is ensured to access only those memory locations
it is authorized to access. Note that administrators might create a security policy that allows
code to bypass this verification step because some code might be designed not to be type-safe
and because some languages do not produce verifiably type-safe code.
NOTE
Microsoft had talked of shipping two JIT compilers: the normal compiler and an econ-
omy version. The basic difference is that the economy version uses fewer resources
(that is, memory footprint and CPU cycles) during the compilation, but produces less
optimized code. As a result, the economy compiler would be useful for platforms
such as Windows CE devices, in which the cost of compilation outweighs the perfor-
mance benefit from fully optimized code. The economy compiler would also be easier
to implement because it uses a straight instruction-for-instruction substitution rather
than a full method and data flow analysis. However, the economy compiler did not
make it into version 1 of the .NET Framework.
.NET Concepts
26
PART I
However, even with this architecture, the execution of your applications when they are first
loaded will be slowed. To prevent this, the CLR also ships with a command-line PreJIT com-
piler (CLR Native Image Generator or ngen.exe) that you can use to precompile your applica-
tion to native code and persist it on disk at installation time. By doing this, your applications
will load much faster although the one-time cost at installation will be increased. The mechan-
ics of doing this are covered in more detail in Chapter 5.
To summarize, refer to Figure 1.3, which outlines the process of compilation and execution of
your VB .NET application. Note that your code is first compiled into MSIL at development
time and then compiled into native CPU instructions at either install time, prior to it (PreJIT),
or at run-time (JITer).
Native Code
Binary file PreJIT Installation MSIL
encoded in a
PE file
Code Execution
Code
Verification JITer
(typesafe)
FIGURE 1.3
A simplified view of the .NET execution environment. The default mode of the CLR uses a JITer that compiles each
method to native code as it is invoked.
The Microsoft .NET Architecture
27
CHAPTER 1
Although using JIT definitely has its costs, there are several scenarios in which JIT might actu- 1
ally improve performance. For example, by its very nature, both PreJIT and a JITer know more
THE MICROSOFT
ARCHITECTURE
about the runtime execution environment than developers who compile their application at
their development workstation far removed from the machine that eventually runs their code.
.NET
As a result, JIT provides the opportunity to include install-time and run-time optimizations; for
example, creating native instructions optimized for the particular CPU (Pentium 4 versus
AMD) and generating efficient code for variables that are not used or that always contain spe-
cific values.
Secondly, the use of JIT means that developers can also expect performance improvements as
new JIT compilers are installed on the machines running their code. In other words, you won’t
have to recompile your code to take advantage of new processor improvements that are added
to JIT compilers. However, it remains to be seen how this will affect support centers that in the
future might have to deal with various JIT compilers.
NOTE
As I’ll discuss later, the Services Framework is organized hierarchically into name-
spaces that are used to group classes as well as other namespaces. The System name-
space contains the core implementations of classes used by the CLR.
.NET Concepts
28
PART I
Object includes virtual, or instance, methods to perform comparison, to create a string repre-
sentation of the object, to clean up in the garbage collection process, to return the type of the
object, and to quickly create a hash value for the object.
NOTE
Hash tables have long been used by C and Perl developers as a quick means of storing
and retrieving values, similar to a collection but with some limitations and better per-
formance. The CLR implements a System.Collections.Hashtable class that uses the
GetHashCode method from System.Object to generate the key value that is placed in
the hash table. The Hashtable class then exposes methods such as Contains and
ContainsKey for finding the key.
In the CTS, all data types (also simply referred to as types) are ultimately derived from
System.Object. At the highest level, all types can be broken down into what are called value
types and reference types. A diagram of how the types are organized can be seen in Figure 1.4.
Object
ValueType ReferenceType
Class B
Byte Int32 (framework, i.e. Multicast
Array) Delegate B
Interface B
DateTime IntPtr (framework,
IDisposable)
Double Single
Uint16 TimeSpan
Uint32 Uint64
FIGURE 1.4
Common Type System. This diagram shows how the CTS is organized. All types are derived from System.Object.
The Microsoft .NET Architecture
29
CHAPTER 1
Value Types 1
Value types are those types that can be described by a series of bits, are typically passed by
THE MICROSOFT
ARCHITECTURE
value within applications, and are used by the CLR to implement many of the intrinsic data
types supported by modern programming languages.
.NET
In the CTS, value types are inherited from System.ValueType. Although they are derived from
System.Object, the value types intrinsic to the CLR do not consume the overhead of tradi-
tional object instances and are stored efficiently. This is because unlike object instances, value
types are allocated in a thread’s stack and not on the garbage-collected heap, which requires
the calculation of pointers to access. For example, the value types in Table 1.1 are typically
implemented as primitive data types in a programming language but are actually implemented
by the CTS.
Keep in mind that each language might not implement the types in Table 1.1 and will not nec-
essarily use the same identifiers for each one. For example, VB.NET does not support
unsigned integers as native types. In Chapter 3, I’ll discuss the mapping of these CTS types to
the types exposed in VB .NET.
.NET Concepts
30
PART I
Value types also have several behaviors that you might expect including
• Default initialization to zero
• Copy by value, in which assigning one variable dimensioned as a value type to another
simply copies the value rather than the address of the value. As a result, two or more
value types cannot refer to the same physical memory address.
In addition to using the intrinsic types, the CTS also supports creating your own value types
that derive from System.ValueType. You might want to do this if you want to create your own
simple data types that are typically passed by value and that you’ll reuse in a series of custom
applications. For example, you might create a value type for a batting average that is used to
store a baseball player’s average and include your own methods for additional calculations.
It should be noted that each time a variable dimensioned as a value type is passed to a method
that accepts an argument of type System.Object, the CLR uses what is called the boxed type
of the variable to create an addressable memory location on the heap for the variable. In other
words, the CLR creates a second representation of the variable (a process referred to as boxing)
so that it can be treated as an object and passed by reference since by definition, a value type is
simply a sequence of bits. When the variable is eventually updated, it is said to be unboxed.
The nice aspect of this behavior is that it provides a unified view of the type system and makes
it possible to write polymorphic code that simply accepts arguments of type System.Object,
but can be used on any value types in addition to actual objects. This is analogous to creating
procedures in VB that accepts Variant arguments so they can work on both simple data types,
arrays, or even class objects.
Although some languages will include special syntax for when you refer to the boxed type ver-
sus the unboxed type such as VC++, in VB .NET you don’t have to worry about explicitly box-
ing and unboxing your code.
NOTE
In some circumstances, you might get small performance improvements if you explic-
itly cast your value types to objects before passing them to a method.
Enumerations
The CTS also implements enumerations (enums) as value types. All enums are derived from
System.Enum. As in VB 6.0, each enum provides a set of named constants (fields) that map to
one of the integer data types (Int16, Int32, or Int64) in the CTS. Enums cannot define their
own methods, implement interfaces, or properties and events. VB .NET fully supports enums,
as I’ll discuss in Chapter 4.
The Microsoft .NET Architecture
31
CHAPTER 1
Reference Types 1
The second type of variable structure that the CTS supports is called a reference type. As you
THE MICROSOFT
ARCHITECTURE
would expect, a reference type is derived from System.Object and is always referenced by its
memory location rather than the actual data that comprises it. In other words, when a reference
.NET
type is created, memory is allocated on the heap and the address is returned and stored in a
variable. Unlike value types, reference types are automatically garbage collected by the CLR,
as will be discussed shortly.
NOTE
The subsystem of the CLR that deals with the manipulation of reference types is
sometimes referred to as the Virtual Object System (VOS). Note that the inclusion
of an object system in the runtime is a unique feature of the CLR and is what gives it
much of its power.
Because reference types refer to the memory address of a variable, two variables can point to
the same underlying object. By default, reference types default to NULL (or Nothing) until
they are initialized. In the CLR, the only primitive data type implemented as a reference type is
System.String. Other uses for reference types include the implementation of classes, inter-
faces and pointers, and delegates.
Classes
Classes are perhaps the fundamental construct in the CTS and are used for just about any kind
of programming endeavor in a managed application, which includes
• Access to all the system services, such as messaging and data access (ADO.NET) as pro-
vided by the Services Framework
• The implementation of the forms package using Windows Forms
• The implementation of Web sites and Web services using ASP.NET
• The implementation of custom code for business logic
• The implementation of custom code derived from the Services Framework
Suffice it to say that all of the code you write in VB .NET will be in the context of a class. In
that respect, VB .NET is not the same procedural language with some object-oriented syntax; it
is now a fully object-oriented language.
As you might expect, classes in the CTS can contain methods, fields, properties, and events,
much like classes in VB 6.0. However, they are much more powerful. As a result, VB has
.NET Concepts
32
PART I
added many keywords that allow it to take advantage of the features of classes in the CTS.
Some of these features include
• Implementation inheritance from a single base class (multiple inheritance is not sup-
ported)
• The ability to create abstract base classes that cannot be instantiated
• The ability to define parameterized constructors on the class that can be called when the
class is instantiated
• The ability to implement one or more interfaces
• Public and private classes
• Overridden methods that are replacements for methods in the base class
• Overloaded methods that have the same method name but different arguments
• Static methods that are shared among all instances of a class and can be called prior to
instantiation
• Synchronized methods that allow only one thread of execution within the method at any
one time
• Methods that are accessible only from within the class and classes that inherit from it
In Chapter 4, I’ll cover the language enhancements to VB .NET that make it possible to access
these features of classes implemented by the CTS.
In some respects, interfaces serve the same purpose as abstract base classes. The difference is 1
that an abstract base class can include functionality within its methods that can be reused by
THE MICROSOFT
ARCHITECTURE
classes that inherit from it. Interfaces, by definition, have no implementation.
.NET
TIP
Because VB.NET now supports both interfaces and abstract base classes, and both can
be used for polymorphism, which one should you use? A good rule of thumb is to use
abstract base classes when there is generic code from which all the derived classes can
benefit and when the derived classes follow the “is a” relationship. In other words,
an abstract base class for Person with a derived class of Employee follows this rule
because “employee is a person.” However, interfaces should be used when the class
that implements the interface will use the same calling semantics but not the same
implementation. For example, an interface called IQuery that includes a GetByID
method could be implemented by both an Order class and an Employee class.
The CTS supports a pointer type as a reference type, which is the value of a machine address
that contains some data. Pointer types cannot be used as if they were objects and, in fact, as in
previous versions of VB, VB .NET does not support syntax to deal with pointers.
Delegates
The CTS also supports a concept called delegates. Delegates can be thought of as an object-
oriented way to create a function pointer. Each delegate forwards calls to a method on some
object instance when the delegate is instantiated. However, because they are implemented as
part of CLR, they are type-safe and always point to valid objects (unlike function pointers in
C++).
The closest equivalent in VB 6.0 to using delegates as function pointers was found in the
AddressOf keyword that developers used to define callback routines when dealing with the
Win32 API; for example, when using the system timer. In the CTS, delegates are used to
implement callbacks. You can also define your own delegates to set up your own callback
schemes, but they also form the basis for all event handling in the CLR. For example, dele-
gates are used in the Windows Forms classes to implement the typical event handlers you
would expect for controls and windows.
Delegates are well suited for events because they can be used to provide the communication
from the source of the event, such as a control on a form, to the receiver of the event, such as
code within the form. When dealing with events, you can think of delegates as the runtime
linking mechanism between an event source and an event receiver.
.NET Concepts
34
PART I
Garbage Collection
As mentioned previously, one of the benefits that the CLR offers is automatic lifetime manage-
ment for objects. This feature is implemented by a garbage collection (GC) algorithm that
cleans up data on the managed heap. Basically, each time an object is instantiated, the CLR
tries to allocate space on the heap for the object. If no space is available, it runs its GC algo-
rithm to try and determine which objects can no longer be referenced and then compacts the
heap before allocating the new memory. As a result, you no longer need to set your object ref-
erences to Nothing in order for their memory to be reclaimed.
NOTE
The process of allocating space on the heap (when there is room and no GC is
required) is very fast. For example, the time needed to create 100,000 small objects in
VB .NET is more than four times faster than creating the same objects in VB 6.0.
When the heap is full, this process will take longer because GC must occur at this
time. As a result, creating designs that require the use of many small objects is not
prohibitive in terms of performance as it was in VB 6. In this way, the CLR assists
developers in designing more purely object-oriented applications.
Of course, by allowing the CLR to manage the lifetime of your objects, by definition it does
not allow deterministic finalization. This means that you cannot write code that will run imme-
diately when the object is set to Nothing because the runtime determines when your object
instances are actually deallocated. In other words, the CLR does not allow you to use
Terminate events in VB and destructors in VC++. Keep in mind that for the purposes of this
discussion, a destructor in VB is the Terminate event.
The way in which the CLR deallocates object instances is through a process called finali-
zation. Internally, when an object is instantiated, the CLR looks to see whether the class has
The Microsoft .NET Architecture
35
CHAPTER 1
THE MICROSOFT
ARCHITECTURE
mines that the object instance is no longer reachable, a thread controlled by the GC runs the
Finalize methods for each of these objects and then removes them from the heap. For the
.NET
CLR, it is much more efficient if your classes do not implement a Finalize method because
the overhead described here could be avoided. However, in many cases, you’ll want to write
code to clean up resources you’ve acquired, such as database connections and file handles.
However, the main problem with nondeterministic finalization is that, by default, you have no
control over when the finalization actually occurs and in what order your objects are deallo-
cated. Obviously, this is a problem that must be addressed and that will affect the way in which
you write your VB .NET code.
As I’ll show in Chapter 4, in these cases, you can implement your own destructor by imple-
menting an interface called IDisposable that contains a method called Dispose. A client
application can then call this method to clean up your object. This method should then call the
Finalize method to clean up your resources and instruct the GC not to finalize this object
because it has already been done.
To programmatically affect the behavior of the GC, in this case and in others, the System
namespace includes a static or shared class called GC. It contains methods to force garbage
collection such as Collect and to suppress the finalization of an object such as
SuppressFinalize, as would be used in the case described earlier.
The CLR also supports a concept known as weak references. These are used when you want,
for example, to place object instances into a collection for future reference. However, you do
not want for the instances to stay alive simply because they are in the collection. By creating
the object variable as a weak reference, the GC will deallocate the instance when all normal
(also called strong) references are gone. A strong reference is simply one created using the
New keyword in the typical way. To create a weak reference, you use the wrapper class
System.WeakReference and pass the variable with the strong reference in the constructor. You
can then subsequently re-create a strong reference from the weak one, if necessary, using the
CType function.
The final concept that affects the GC is resurrection. Simply put, resurrection allows an object
instance from within its Finalize method to create a new reference to itself in another vari-
able. At this point, the GC cannot deallocate it, so the instance is said to be resurrected. When
the resurrected instance is finally garbage collected, the GC will not by default call the
object’s Finalize method a second time. To ensure that it is called, you can call the GC’s
ReRegisterForFinalize method and pass it a reference to the object from within Finalize.
Although resurrection is possible, there are few if any cases in which you would actually want
to implement it.
.NET Concepts
36
PART I
Component Metadata
As VB 6.0 developers, you’re probably familiar with the concept of using the References dia-
log from the Project menu to reference a component, coding against it using IntelliSense, and
using the Object Browser to view its method and property signatures. Until now, I haven’t dis-
cussed how or where this information exists in .NET, although Figure 1.3 certainly implies that
one VB .NET application can, for example, reference and make use of classes declared in
another application. In fact, using the System namespace and its classes is just such an example
of referencing code from MSCorLib.dll.
The answer is that all the information that VB 6.0 developers found in type libraries, IDL, and
the use of Regsvr32 is incorporated directly in the PE file (module) that contains the classes to
be used in the same way that type libraries are automatically compiled into an unmanaged VB
6.0 COM component. This data, which includes declarations, implementations, and references
specific to the module, is referred to as component metadata. This technique allows managed
code to be self-describing.
Tools such as VS .NET provide a References dialog that allows you to select the managed code
to reference. This process reads the metadata from the component so that VS .NET can provide
IntelliSense and early binding.
NOTE
As you’ll see, the selection of code in this process actually occurs at a higher level
called an assembly (described later), and not for individual modules.
Keep in mind that selecting the component and using its metadata during development does
not affect the deployment of the application. Even though at design-time you add a reference
to a local component, at run-time you can configure your application to find the component
across the network or across the Internet.
NOTE
Not surprisingly, the System namespace also contains classes—Reflection and
Reflection.Emit—that you can use to inspect metadata at run-time in order to
dynamically instantiate objects and to actually emit metadata to a PE file, respec-
tively. Most corporate developers will not utilize these classes, so they are beyond the
scope of this book. For more information, review the .NET SDK samples on
Reflection.Emit and Reflection.
The Microsoft .NET Architecture
37
CHAPTER 1
Run-time Components 1
The two main run-time components of the CLR with which VB .NET developers need to be
THE MICROSOFT
ARCHITECTURE
familiar are assemblies and application domains. As you’ll see, both have big implications for
.NET
how VB .NET developers construct, package, and execute their applications.
Assemblies
A proper understanding of assemblies is critical for developing VB .NET applications. First
and foremost, all MSIL code executed by the CLR must exist in an assembly, which therefore
can be thought of as a versionable, self-describing, and reusable building block for a .NET
application. .NET applications are made up of one or more assemblies. More specifically, an
assembly is a collection of one or more modules (.dlls, .exes, resource files such as bitmaps)
that form a security boundary, are the smallest unit of deployment and versioning, and form
the boundary for types. In other words, a class (type) that you declare in an assembly is differ-
ent from all other types even if its name is the same as a type from a different assembly. The
rules associated with assemblies are also what allow the CLR to enable side-by-side execution
where multiple versions of the same assembly can be run both on the same machine and even
within the same process. These rules and the process used to load assemblies are the key to
ending “DLL Hell,” where the installation of a new version of a component breaks existing
applications. However, before getting ahead of ourselves, let’s look at the manifest.
Manifest
For the assembly to be self-describing, it must contain some metadata that specifies informa-
tion on all items in the assembly, the items that can be accessible outside the assembly, and a
collection of references to other assemblies. This data is referred to as the manifest and con-
tains the following information.
• A string name for the assembly.
• Version information in four parts and referenced as major version.minor
version.revision number.build number. The CLR uses the version number to deter-
mine which assembly to load at runtime.
• Shared name information. This includes a public key and a hash of the file containing the
manifest signed with a private key. Creating a shared name (also referred to as strong
name) is optional, but is used for tighter security and guarantees name uniqueness. In
some cases, such as when you want more than one application to use the assembly on
the same machine (referred to as a global assembly), you must create a strong name.
• Culture (locale), processor, and operating systems supported.
• A list of all files in the assembly using relative pathing. This implies that all files in the
assembly must be in the same directory or subdirectory as the manifest.
.NET Concepts
38
PART I
• A list of other assemblies that are referenced within this assembly including the name,
some metadata (such as version and culture), and the public key if the assembly is
shared.
In the simple case where the assembly consists of a single binary file (module), the manifest is
compiled into the PE file by the VB .NET compiler. You’ll notice in Figure 1.2 that ILDasm
allows you to view the manifest information. In assemblies that contain more than one file, the
manifest can be stored in one of the files or in a separate file using the Assembly Linker
(AL.exe) command-line utility.
In addition to the required information in a manifest, developers can also include information
such as the company, description, title, trademark, and copyright. This information must be
specified by the developer using attributes and is provided automatically in VS .NET through
the inclusion of an AssemblyInfo.vb file in the project.
Attributes
As will be discussed in Chapter 2, attributes are new to VB developers and are simply
additional information that decorate methods, classes, modules, or the assembly. The
CLR and compilers use attributes to make decisions at compile and run-time regard-
ing the behavior of the code. Attributes allow developers to declaratively ensure
that their code is used in a particular way. For example, an attribute can decorate a
class that will use COM+ services to specify that the class requires the creation of a
new transaction. Another example is the attribute that is used at the assembly level
to specify the file that contains the key pair used to create a strong name.
Versioning
As mentioned earlier, assemblies are the smallest unit of versioning in the CLR and have a
four-part numbering structure called the compatibility version number. Assemblies can also
contain a text string that is used for documentation purposes and that contains the textual
description of the version. This information is created automatically by VS .NET, but can also
be specified using an assembly attribute called AssemblyVersion from the System.Reflection
namespace.
The compatibility number is used by the CLR when making decisions about whether to load
the assembly when it is referenced by another assembly. Note, however, that this is done only
when the assembly has been created with a strong name and is therefore intended for sharing.
Assemblies that are compiled without a strong name are referred to as private assemblies and
must be distributed in the application directory.
The Microsoft .NET Architecture
39
CHAPTER 1
For example, assume that assembly A uses a class from shared assembly B. At compile time, 1
the manifest of assembly A contains a reference to the compatibility number of assembly B. At
THE MICROSOFT
ARCHITECTURE
run-time, the CLR goes through several steps, discussed later, to find assembly B. When the
CLR finds assembly B, it compares its major and minor versions with those in the manifest. If
.NET
they differ, the assembly by definition is incompatible and the CLR will not use it. If they are
the same, the CLR checks the revision number. If the revision numbers differ, the assembly
might be compatible but by default the CLR will use it anyway.
CAUTION
In the case where the revision and build numbers have changed, the CLR does not
guarantee that the newer revision is backward-compatible. That is why it “might be
compatible.” Note that this is different from the COM specification where a compo-
nent was loaded only if the interfaces it implemented had not changed. This self-
versioning scheme ensured backward-compatibility but did not allow side-by-side
execution.
The build number is often referred to as the Quick Fix Engineering (QFE) number and will
always be seen as compatible by the CLR. This allows developers to create quick fixes to
assemblies without requiring dependent assemblies to be recompiled.
The scenario described in this section assumes the default versioning policy but this can be
changed by the presence of configuration files.
Configuration Files
During the process of loading an assembly, the CLR can use information found in configura-
tion files to assist it. The application configuration file is identified by having the same name
as the application except with a .config extension or for Web applications be specified in the
Web.config configuration file. This XML file contains a root element called <configuration>
and child elements <runtime>, <assemblyBinding>, <dependentAssembly>,
<publisherPolicy> and <probing>. Perhaps the best method to illustrate the use of an appli-
cation configuration file is through an example.
TIP
Note that all elements, attributes, and values in the configuration files are case
sensitive.
.NET Concepts
40
PART I
Let’s assume that, as in the previous scenario, the CLR is attempting to load the shared assem-
bly B. However, assembly A has an A.config file in its application directory. The file might
look as shown in Listing 1.1.
LISTING 1.1 A sample application configuration file used by the CLR to make decisions
about how to load assemblies at run-time.
<configuration>
<runtime>
<assemblyBinding xmlns=”urn:schemas-microsoft-com:asm.v1”>
<probing privatePath=”bin;bin2 “/>
<publisherPolicy apply=”yes”/>
<dependentAssembly>
<assemblyIdentity name=”B”
publickeytoken=”32ab4ba45e0a69a1”
culture=”en-us” />
<bindingRedirect oldVersion=”*”
newVersion=”5.3.1.1”/>
<codeBase version=”5.3.1.1”
href=”http://www.quilogy.com/bin/b.dll”/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
In this example, the configuration file first specifies in the <probing> tag several relative paths
that should also be used when searching for assemblies using privatePath.
In the <assemblyBinding> tag, the <publisherPolicy> element is used to specify whether the
application must run only with the original versions of other assemblies with which it was
tested and compiled. If apply is set to “no” all other policies in the file and any configuration
information specified by the publisher is ignored. The default mode is “yes,” which means that
the other information specified in the <assemblyBinding> tag will be used.
The <assemblyBinding> tag includes a <dependentAssembly> element that includes child
elements that specify how to handle reference to the assembly identified in the
<assemblyIdentity> element. In this case all references to assembly B should be redirected
per the <bindingRedirect> element to use version 5.3.1.1 as noted in the newVersion
attribute. Other attributes specify the publickeytoken (which is a hash of the public key) for
the shared assembly B and the oldVersion, which should be redirected (in this case, all of
them *).
The Microsoft .NET Architecture
41
CHAPTER 1
The <dependentAssembly> tag includes a <codeBase> element that specifies a new location 1
from which to download assembly B. This location will be tried before any other attempts are
THE MICROSOFT
ARCHITECTURE
made.
.NET
At a higher level the CLR will also examine a publisher policy file if one exists and the
<publisherPolicy> is set to “yes.” This file might be distributed by a publisher along with a
shared component and can be used to redirect the assembly reference to a new version. If used
by the CLR, information in this file overrides that found in the application configuration file.
Administrators can also specify configuration information by placing binding information in
the Machine.config file in the Config directory of the root directory where the runtime is
installed (typically <windows directory>\Microsoft.NET\Framework\<version>\CONFIG>).
This file can contain all the same tags as in the application and publisher configuration files
but will, of course, override any other settings.
NOTE
As discussed in Chapter 5, the .NET Admin tool can be used to create both application
and administrator settings.
First, if a <codeBase> is found in the config file, it uses the information to attempt to download
the assembly and make sure that it can be loaded by checking its version, culture, and public
key as specified in the tag. Note that if the download fails, the process ends at this point and an
exception is thrown. In other words, if a codebase hint is specified, it is the only way the
assembly can be loaded.
A second interesting behavior the class loader supports is that it remembers the codebase for
the assembly. So, for example, if assembly A is downloaded and refers to assembly B, which
must be subsequently loaded, the class loader will look at the URL from which it retrieved
assembly A to find assembly B. In this case, however, if assembly B is not found in that loca-
tion, the rest of the process described later continues.
If the hint is not present, the class loader proceeds to use a process called probing. Probing
begins by searching for files in the application directory with the name of assembly and exten-
sions of .exe, .dll, or .mcl. It then moves on to the directories relative to the application direc-
tory specified in the application configuration file’s <probing> tag. The class loader also takes
into consideration the culture of the assembly and automatically searches within subdirectories
for the culture. For example, if the culture (locale) of assembly B is Deutsch (de), the class
loader looks for a subdirectory de under each directory it eventually searches.
Note that probing is used to find both private and shared assemblies and that for private assem-
blies, if the assembly is not found at this point, an exception is thrown. However, for shared
assemblies (those with a public key) the class loader also looks in the Global Assembly Cache
(GAC). The GAC is a storage area under <windows directory>\ assembly that is used to store
shared assemblies that can be used by more than one application on a particular machine. .NET
ships with a command-line utility (GACUtil.exe), Windows shell extensions, and the .NET
Admin tool that allow you to place your assembly in the GAC. Although the GAC is analogous
to registering components in the registry, the GAC can store multiple versions of the same
assembly and is very tightly coupled so that the contents of the GAC are always synchronized
with the registration information.
For shared assemblies, then, the class loader looks in the GAC to see whether a version exists
with a higher build and/or revision number and to consult a publisher policy file if one exists.
If so, the version from the GAC is loaded even if the assembly was previously found during
probing. This ensures that assemblies in the GAC have higher priority. If a match is found in
the GAC, the assembly will be loaded.
Administrator Policy
Finally, the Machine.config file is consulted for any possible version redirection. If one is
encountered, the class loader does not go through the entire probing process again but simply
looks for the assembly in the GAC. If it is found, the assembly is loaded.
The Microsoft .NET Architecture
43
CHAPTER 1
Security 1
To accommodate modern distributed applications, security in the .NET world is more complex.
THE MICROSOFT
ARCHITECTURE
We’ll explore many of these issues in Chapter 5, but for now the key point is that security
information—such as the permissions the assembly needs to run—is compiled into the assem-
.NET
bly manifest. This is referred to as code-based security. At run-time, the CLR uses this infor-
mation in conjunction with security policies set by the administrator to determine whether the
code should be allowed to run.
Secondly, a shared assembly is verified at load time to ensure that it has not been altered since
it was compiled. It can do this by comparing the hash value of the file stored in the manifest
with a hash performed at load time of the actual file. If the two do not match, the assembly file
is not loaded. In addition, the CLR validates the assembly’s signature by using the public key.
Application Domains
The final concept—and the highest level explored in this section—is that of application
domains. Application domains (or app domains), as the name implies, are boundaries created
by the CLR in which applications run. App domains are isolated from each other, for example,
by providing a security boundary between domains, providing fault tolerance where one app
domain cannot bring down another, and making sure that code loaded in one app domain can-
not directly access code in a second app domain.
App domains do not map directly to Win32 processes but can be thought of as lightweight
Win32 processes that don’t incur the overhead of context switches and other operating system
overhead. Many app domains can coexist in the same process created by a runtime host. Note
that this architecture is much different than was the case historically, when separate processes
were used as the fundamental boundary between applications. Several of the advantages to app
domains include the fact that applications can be stopped and started without taking down the
entire process, and that the code from an assembly that is used by multiple app domains in the
same process must be loaded only once.
.NET Concepts
44
PART I
However, app domains are also not analogous to threads because many different threads can
run the code in a single application domain (in the case of a managed COM+ component) or
the same thread can run code in several application domains (in the case of a Web server).
NOTE
The responsibilities of the runtime host include loading the CLR, creating the app
domains, and loading the user code within the app domain. Runtime hosts include
ASP.NET and Internet Explorer, among others. In fact, you can write your own run-
time host using the unmanaged APIs that ship with the .NET Framework and are
described in the online documentation.
The way the CLR uses application domains in the two most common scenarios is as follows.
For console, services, and Windows Forms applications, by default a single app domain is cre-
ated for each application in separate Win32 processes. For Web applications, each Web site is
created within its own app domain inside the Web server process.
Note that individual applications can programmatically spawn new app domains. The System
namespace supports an AppDomain class that allows developers to programmatically create and
manipulate domains. For example, an application that instantiates an object can request to have
it loaded in a separate app domain for isolation. In this case, a proxy and stub arrangement
analogous to that found in classic COM is used to facilitate communication. These concepts
collectively are called .NET remoting and will be discussed in Chapter 8.
Class Libraries
Much of the discussion in this chapter has referred to the System namespace and classes within
it. In this section, I’ll formally introduce the concepts of namespaces and the Services
Framework and their implications for VB. NET developers.
Namespaces
VB developers who are familiar with dot notation should have no trouble envisioning the con-
cept of a namespace. Basically, .NET uses namespaces in two ways:
• To organize (scope) code within and among assemblies into collections of functionality
• To expose that organizational unit to other applications so that they can “import” it at
design time
Each assembly can contain multiple namespaces, and each namespace can contain multiple
classes or even other namespaces. Therefore, the AsymmetricAlgorithm class nested within the
The Microsoft .NET Architecture
45
CHAPTER 1
Cryptography namespace nested within the Security namespace within the System name- 1
space and found in the system assembly is denoted as
THE MICROSOFT
ARCHITECTURE
System.Security.Cryptography.AsymmetricAlgorithm
.NET
Each project you create in VS .NET will automatically have a default or global namespace that
is the same as the project name and, ultimately, the assembly name. However, you can create
your own namespace hierarchy as you see fit. In addition, you can also create nested name-
spaces that span assemblies as is done in the Services Framework. For example, you can create
an assembly that contains the Quilogy namespace that exposes some high-level classes and
then subsequently create a namespace in a different assembly called Quilogy.Utils. When a
client program references both assemblies, the namespaces will be grouped together by
IntelliSense. However, in this case, you’ll need to be sure that you don’t create name collisions
by creating a class called Utils in the original Quilogy assembly.
NOTE
Many of the chapters in the book (especially those in Part II) will use examples from a
distributed application that the company I work for, Quilogy (www.quilogy.com) could
implement using .NET. Quilogy is a services company that offers digital consulting,
managed hosting, and technical education. Many of the examples relate to a Web
application for handling student enrollment in our technical education courses.
It should also be pointed out that there is nothing to prevent name collisions between name-
spaces created by different companies. For example, two companies called Smith Brothers
could create SmithBros namespaces. When the assemblies are used together in a client pro-
gram, there is currently no way to disambiguate the reference. As a result, you should try to
specify as unique a name as possible for your namespaces, perhaps starting with your com-
pany’s Web site address.
Services Framework
As discussed previously, the goals of .NET include a simplified and unified programming
model. One of the ways this has been accomplished is with the inclusion in .NET of the
Services Framework.
The Services Framework contains namespaces developed by Microsoft that encapsulate the
core functionality of the CLR and often-used system services. In fact, much of this book is
about showing you techniques used with the classes of the Services Framework. To give you a
short introduction to the kinds of functionality supported, Table 1.2 lists the key namespaces
found in the Services Framework and how they fit into this book.
.NET Concepts
46
PART I
TABLE 1.2 Services Framework namespaces. These namespaces are explored in more
detail throughout this book.
Namespace Description Chapter(s)
Discussed in
Microsoft.VisualBasic Contains VB specific Throughout
keywords
System.Security Used to implement 5, 8
declarative (using attributes)
and imperative (within the
method code) security
within code
System.Diagnostics Used to perform system 6, 12, 13, 14
monitoring; that is,
processes, performance
monitor, and the Event Log
System.Data Used to communicate with 7
data providers
Microsoft.Win32 Used to interface with the 8
Win32 API.
System.EnterpriseServices Used to create components 9
for use in COM+
System.Runtime. Used to interact with COM 8,9
InteropServices and the Win32 API
System.Runtime.Remoting Used to communicate with 8
other managed applications
System.Web.UI Used to create interfaces for 10
Web applications
System.Web.Services Used to create Web services 11
System.IO Used to interact with the file 12
system
System.Threading Used to create and manage 12
multiple threads of execution
System.Security. Used to encrypt and decrypt 12
Cryptography programmatically
System.Timers Used to set up and monitor 13
system timers
The Microsoft .NET Architecture
47
CHAPTER 1
THE MICROSOFT
ARCHITECTURE
System.Net Used to communicate with 13
.NET
Web protocols
System.XML Used to load and manipulate 14
XML documents
programmatically
System.Messaging Used to interact with 14
Microsoft Message Queue
System.DirectoryServices Used to interact with 14
directory services
Obviously, the Services Framework is large, containing over 80 high level namespaces and
over 1,200 classes, and no single book can explore all of its aspects. That’s why this book is
focused on those aspects of the Framework used to build distributed business systems in VB
.NET by giving you techniques you can reuse.
However, one of the key benefits of the Services Framework for organizations is that they can
provide language-independent training on the framework for their developers working in any
of the CLR-supported languages. In addition, the Services Framework contains common pro-
gramming patterns and conventions that not only unify the framework from a programmer’s
perspective, but act as a template for the design of custom class libraries.
Summary
Obviously, building distributed applications in VB .NET is, in many respects, going to be a
whole new ballgame. As a result, this chapter tried to provide a firm foundation by taking you
through both the reasons for the changes and a first look at how the internals work. Hopefully,
you’ll be better able to put in context the chapters that follow.
To begin, we’ll look at the changes to Visual Studio .NET and particularly the IDE that will
assist you in building great distributed applications. To that end, let’s get started.
The Development Environment CHAPTER
2
IN THIS CHAPTER
• A New IDE 50
• Using Attributes 73
• Command-Line Compilation 76
.NET Concepts
50
PART I
As mentioned in Chapter 1, “The Microsoft .NET Architecture,” one of the goals of the .NET
initiative is to unify the various programming models developers have used to build a complete
solution. This unification also is extended to the integrated development environment (IDE),
Visual Studio .NET. The unification of the Visual C++, Visual Basic, and Visual
Interdev/Visual J++ development environments means that all developers on the Microsoft
platform have access to the same sets of tools—for example, the integrated debugger and
macro facilities—thereby leveling the playing field. In addition, a single environment should
make training and team development within your organization simpler, as well.
The IDE that served as the basis for the VS .NET IDE was the Visual Interdev/Visual J++ IDE
that shipped with Visual Studio 6.0. As you’ll see, it has been extended to include a variety of
new features that VB .NET developers can take advantage of while retaining a familiar feel for
VB developers.
NOTE
Incidentally, VS .NET itself is an example of an application that combines both man-
aged and unmanaged code. The core of VS .NET was written in unmanaged code, but
many of the new features discussed in this chapter were written in managed VC#
.NET.
This chapter takes a quick tour of the IDE and is designed to get the VB developer up to speed
quickly to begin using VB .NET productively.
NOTE
All code listings and supplemental material for this chapter can be found on the
book’s Web site at www.samspublishing.com.
A New IDE
One of the first things you’ll notice when executing VS .NET, because it appears first, is the
Start page. This page is “home base” for VS .NET and is used to review and open projects, as
well as act as a conduit for information from Microsoft. For example, the links on the left side
of the page include an Online Community link, which provides a list of Web resources includ-
ing newsgroups; a Headlines link, which displays the current headlines from
msdn.microsoft.com; a Search Online link, which allows you to search the MSDN online
library; and a Downloads link, which provides links to additional Web releases and public
betas that can be downloaded.
The Development Environment
51
CHAPTER 2
NOTE
In addition, look for Microsoft to offer links to third-party services from the Start
page as well. For example, the Web Hosting link provides information about hosting
ASP.NET applications with various application service providers. From here, you can
find more information or set up a relationship with one of the preferred hosting
vendors.
However, the most important link on the Start page is the My Profile link. This page allows 2
you to customize the keyboard scheme, window layout, and help filter and combine these set-
DEVELOPMENT
ENVIRONMENT
tings in a custom profile. In addition, predefined profiles that match the various Visual Studio
THE
developers (Visual Basic, Visual C++, Visual Interdev, and so on) are available. As a starting
point, I’m sure many VB developers will choose the Visual Basic profile as they become famil-
iar with the IDE.
Finally, the At Startup option also can be used to control whether the Start page is even shown,
or whether VS .NET automatically loads the last project or displays an open project dialog.
The remainder of this section discusses creating and managing projects using the various fea-
tures of the IDE including the IDE windows, supported file types, referencing other projects,
and using macros and add-ins.
TIP
The Project Build Order menu option only appears if you have multiple projects in
your solution.
Additionally, solutions can be used to manage files related to the projects, but not actually con-
tained in them. For example, you can add readme files to the solution so that you can edit and
work with them from within the IDE. A solution typically is comprised of both a .sln file for
.NET Concepts
52
PART I
storing the project references and build configuration, and a .suo file for storing IDE configura-
tion settings.
NOTE
A solution is analogous to a group (.vbg) in previous versions of VB.
Creating a Project
The first step in creating a project is to click on File, New Project. The resulting dialog con-
tains Project Types on the left and various templates within each type on the right. The project
templates allow you to create projects that support the two primary programming models in
.NET—Windows Forms and ASP.NET—in addition to ancillary project types. Table 2.1 lists
the basic templates in the Visual Basic Project folder that ship with the professional version of
VS .NET.
DEVELOPMENT
ENVIRONMENT
Windows Service Used to build Windows Service applications, discussed in
Chapter 13, “Implementing Services.” Creates a template
THE
service derived from
System.ServiceProcess.ServiceBase.
Empty Projects You can create both empty local projects and empty Web
projects. This might be useful when moving projects from
one machine to another so that you don’t have to delete the
template files created for each project.
NOTE
Note that Visual Studio .NET Enterprise Developer and Visual Studio Studio .NET
Enterprise Architect ship with additional templates. For example, under the Other
Project node in the list of project types are Enterprise Template Projects including the
Visual Basic Distributed Application template. These enterprise templates provide
architectural guidance, access to application and database modeling features, and
definition of policies connected to a solution. They allow an organization to cus-
tomize the IDE, among other things. Many organizations will want to use these fea-
tures; however, this book will focus on only those templates and features found in
the professional edition.
The dialog also contains options as to whether the new project will be created in the existing
solution or a new one. The default is to create a new solution in which the project lives in the
directory shown in the dialog.
TIP
Additional projects also can be added to the solution by using the Add Project option
on the File menu, rather than New Project.
.NET Concepts
54
PART I
As mentioned, one advantage to using solutions is to be able to work with multiple projects
simultaneously, so that, as in VB 6.0, one project can reference code from another. This behav-
ior typically is used to create test harness projects for unit testing your assemblies.
Web projects also can be taken offline by clicking on the Work Offline option on the
Project, Web Project menu. Taking a project offline copies its files to a directory under
the directory shown in the Options dialog in the Web Settings panel. You then can
edit the files locally and subsequently compare and synchronize them with the Web
server using options under the Project, Web Project menu.
Finally, unlike other types of projects, Web projects can be copied using the Copy
Project menu option on the Project menu or the toolbar button on the Solution
Explorer window. The resulting dialog allows you to specify a destination project
folder and copy all files or a subset of them using either the FrontPage or file share
Web access method.
2
DEVELOPMENT
ENVIRONMENT
THE
In addition to the project templates shown in Table 2.1, VS .NET includes a series of setup and
deployment project templates, as well. These will be discussed in Chapter 5, “Packaging,
Deployment, and Security.”
When the project is created, its definition is stored in a .vbproj file in the appropriate directory.
As you might expect, this file is simply an XML file that contains the project information.
IDE Windows
After the project type has been selected and loaded, you can work with the project using the
various windows discussed in this section. Figure 2.1 shows the primary windows.
Solution Explorer
Once inside a project, the main window used for navigating the project is the Solution
Explorer. Typically situated in the upper right-hand corner of the screen, it contains three
views: File (default) view, Class view, and Resource view.
The default view includes the files and directories that comprise the project, in addition to the
additional project references including both local and Web references. Obviously, from here,
you can edit the various files in the project in both Design and Code views by double-clicking
on them or highlighting the appropriate file and using the toolbar buttons on the window.
TIP
To view files that are typically hidden in the File view, you can click the Show All Files
button in the toolbar. This is useful, for example, for viewing the compiled and refer-
enced assembly files in the bin directory in addition to providing direct access to the
code behind files used with ASP.NET pages, as we will discuss in Chapter 10.
.NET Concepts
56
PART I
FIGURE 2.1
The primary windows used in VS .NET.
As mentioned, the Solution Explorer also supports Class and Resource views, which can be
accessed using the View menu. The Class view presents a hierarchical view of the projects,
namespaces, classes, and members in the solution, and allows you to group them or sort them
alphabetically, by type and by access level. By double-clicking on any node in the tree, the
code editor window displays the definition. Obviously, this can be an efficient way to traverse
your code and can take the place of using the drop-downs on the top of the code editor as is
traditionally done, because the Class view displays the entire project rather than a single class.
The Resource view displays the resource files included in the project and hierarchically shows
the types and the resources within each file.
Properties
As in VB 6.0, the Properties dialog displays the properties associated with whatever object is
currently highlighted in the Solution Explorer, visual designer, or code editor window. It
appears in the lower right-hand corner of the screen with the dynamic help window, but as with
the other windows, it can be undocked and moved to another location. Obviously, properties
that are not disabled can be set at design time simply by clicking on the property and directly
changing its value. Some properties also provide special property editors that allow you to
graphically set the property, such as the color editor used with properties, as in BackColor.
The Development Environment
57
CHAPTER 2
Toolbox
The Toolbox window displays on the left-hand side of the screen and, when using the Visual
Studio Developer profile, it is set to auto-hide and only appears when you place your cursor
over the small preview window or use the View, Toolbox menu.
When the toolbox is displayed, it is comprised of a series of tabs. In addition to the General
and Clipboard Ring tabs, which always are there, which tabs appear and which components are
enabled depend on the type of project you’re working on, what is selected in the development
environment, and whether an Enterprise Template policy is in effect.
2
TIP
DEVELOPMENT
ENVIRONMENT
The Toolbox goes away when you move your cursor off it or click elsewhere in the
THE
IDE. To keep it open, turn off Auto Hide using the thumbtack icon or the menu
option on the Window menu when the Toolbox has the focus. This applies to all
other windows, as well.
As with previous versions of VB, you can drag and drop items from the Toolbox onto a
designer surface, such as a Web Form. However, note that the Toolbox also contains tabs that
include inherently nonvisual components, such as event logs and performance monitor coun-
ters. These types of components can be dragged onto the designer and automatically generate
the template code to use the component within the .vb file.
To customize the Toolbox, you can right-click on it and add a tab, sort, add and delete compo-
nents on a tab, show all the available tabs, and rename tabs. The Customize Toolbox dialog,
that is invoked by right-clicking on the Toolbox and choosing Customize Toolbox, displays
both classic COM components, as well as .NET components installed on the current machine.
The Reset button allows you to restore the contents of the Toolbox to the state it was when VS
.NET was first launched.
One interesting functionality of the Toolbox that was not available in VB 6.0 is the capability
to store text (fragments) on any of the tabs by simply highlighting the text in the code editor
and dragging and dropping it onto the tab. You then can rename the item and subsequently drag
it into other pages. This simple form of reuse can be handy for frequently used programming
constructs such as loops and conditional logic.
Code Editor
The majority of time a developer spends with the IDE is spent in the code editor. Luckily, the
editor in VS .NET contains the same powerful features that VB developers are used to, in addi-
tion to several new features.
.NET Concepts
58
PART I
The first point to note is that, as in VB, the code editor typically is invoked only after the
graphical designer has been opened. For example, by default, when you double-click on a file
in the Solution Explorer, its designer is loaded and the Web page, form, or component designer
is displayed. In some instances, the designers themselves contain more than one view. For
example, when editing a Web Form, the designer supports both a graphical view and an HTML
view accessed through tabs found at the bottom of the view. Both views affect the visual inter-
face, so they are logically a part of the designer. However, the code that executes behind the
form then can be accessed by double-clicking on the designer, using the context menu, or as
noted earlier, using the toolbar button in the Solution Explorer window.
TIP
When editing a Web page in HTML view, the code editor window also contains two
buttons in the upper right-hand corner. These can be used to toggle between Full
HTML view and Script Only view so that you can edit only the server- and client-side
script blocks in your code.
After the code editor is opened, it contains the familiar drop-downs at the top used to create
handlers for events. The drop-down on the left displays the current class and any class-level
variables declared using the WithEvents keyword. On the right, you’ll find the events exposed
for the currently selected object. In addition, the drop-down on the left contains the Overrides
and Base Class Events items. The former is used to show a list of the methods on the left that
can be overridden from the base class if one exists, whereas the latter shows a list of events
that can be handled. By selecting one of these, a new method definition that uses the
Overrides keyword (which will be discussed in Chapter 4, “Object-Oriented Features”) or an
event handler using the Handles keyword is created.
Notice that in both drop-downs, small icons are placed in front of the objects and members to
indicate the access level (explained in Chapter 4) and type of the object or member, as shown
in Figure 2.2.
FIGURE 2.2
The icons displayed in the code editor drop-downs.
The Development Environment
59
CHAPTER 2
In Figure 2.2, protected members, such as Page_Init are specified with a key, private members,
such as IntializeComponent include a padlock, and public members simply have a cube.
One of the more visible new features of the code editor includes the outlining capability that
uses the concepts of regions. To define a region, you can use the #Region and #End Region
declarations to wrap a section of code. This region then can be collapsed and expanded to
more easily navigate the code. The Outlining menu options on the Edit menu or accessed
through the context menu also can be used to collapse and expand the regions.
Although VB developers always have been accustomed to a certain level of code reformatting
in terms of keyword capitalization and text highlighting, the code editor now supports two lev- 2
els of automatic indentation (block and smart) and the capability to insert spaces, as well as
DEVELOPMENT
ENVIRONMENT
tabs. These options and others (such as line numbering) that affect the editor can be found in
THE
the Options dialog invoked from the Tools, Options menu in the Text Editor, Basic panel.
As in VB 6.0, full IntelliSense also is supported by default, including listing of members, para-
meter information, quick information, and statement completion. It can be explicitly invoked
using the Edit, IntelliSense menu. IntelliSense defaults also can be set in the Text Editor, Basic
panel.
NOTE
One feature that VB .NET developers wanted to be included, but that didn’t make it
into the released product, is XML comments. By placing comments in predefined XML
tags, they can be included by the compiler into metadata that is subsequently dis-
played by IntelliSense and the Object Browser when the component is used. Although
this is a great feature, it adds to the size of the code and reduces readability, so look
for Microsoft to take a different approach in a future release.
Server Explorer
Perhaps the most interesting new window in the IDE is the Server Explorer. It appears in the
same location as the Toolbox and behaves in the same manner in terms of its autohide setting.
The concept behind the Server Explorer is to give graphical access to components that devel-
opers need to interact with, either on their machine or, more likely, on a server. In this way, the
Server Explorer is definitely geared toward the middle-tier developer who needs to program-
matically access reporting, message queues, event logs, performance counters, services, and
SQL Server databases.
For example, to use the Server Explorer, simply click on View, Server Explorer, and the win-
dow appears. By default, the window shows the current machine, but can be used to access
.NET Concepts
60
PART I
additional machines by right-clicking on the Servers node in the tree view and selecting Add
Server. By drilling down into the server of interest, you can inspect the various components
and then drag and drop one onto a designer surface. For developers building middle-tier com-
ponents, this can be done by adding a new component to the project, which creates a class
derived from System.ComponentModel.Component. This class allows the component to expose
the Component Designer surface where components can be dragged and dropped. By dragging
a component onto the surface, a visual representation of it appears on the designer while code
is added to the class.
To illustrate the code created during this process, Figure 2.3 shows the Component Designer
just after a SQL Server stored procedure called usp_GetStudent has been dropped onto the
surface. Because the component is nonvisual only, an icon appears on the surface analogous to
using the Internet or Mail controls that shipped with VB 6.0.
FIGURE 2.3
The Component Designer surface after dragging and dropping a component.
However, behind the scenes, two members were added to the class, and the
InitializeComponent method was created to initialize objects that correspond with the com-
ponents that were dropped. All the code is contained in a region that is collapsed by default.
The results can be seen in Listing 2.1.
The Development Environment
61
CHAPTER 2
LISTING 2.1 Autogenerated Code. This code is generated by the Server Explorer to
execute a SQL Server stored procedure.
#Region “ Component Designer generated code “
DEVELOPMENT
ENVIRONMENT
Friend WithEvents SqlCommand1 As System.Data.SqlClient.SqlCommand
THE
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.SqlConnection1 = New System.Data.SqlClient.SqlConnection()
Me.SqlCommand1 = New System.Data.SqlClient.SqlCommand()
‘
‘SqlConnection1
‘
Me.SqlConnection1.ConnectionString = “data source=SSOSA;” & _
“initial catalog=Enrollment;integrated security=SSPI;persist sec” & _
“urity info=True;workstation id=SSOSA;packet size=4096”
‘
‘SqlCommand1
‘
Me.SqlCommand1.CommandText = “dbo.usp_GetStudent”
Me.SqlCommand1.CommandType = System.Data.CommandType.StoredProcedure
Me.SqlCommand1.Connection = Me.SqlConnection1
Me.SqlCommand1.Parameters.Add(New System.Data.SqlClient.SqlParameter( _
“@RETURN_VALUE”, System.Data.SqlDbType.Int, 4, _
System.Data.ParameterDirection.ReturnValue, True, CType(10, Byte), _
CType(0, Byte), “”, System.Data.DataRowVersion.Current, Nothing))
Me.SqlCommand1.Parameters.Add(New System.Data.SqlClient.SqlParameter( _
“@StudentID”, System.Data.SqlDbType.Int, 4, _
System.Data.ParameterDirection.Input, True, CType(10, Byte), _
CType(0, Byte), “”, System.Data.DataRowVersion.Current, Nothing))
End Sub
#End Region
In Listing 2.1, because executing a stored procedure requires a connection to a database, two
objects, an ADO.NET SqlConnection and SqlCommand, are created. (We will discuss this in
.NET Concepts
62
PART I
more detail in Chapter 7.) You can graphically change the names of these components and their
properties using the Properties window, and the corresponding code will be rewritten.
Although using the Server Explorer in this manner can speed up the development process, it
also is good for learning how to use some of the Services Framework. In many instances, you
might not want to inherit from Component, so the code generated here can simply be copied
and used elsewhere. Also notice that the generated code is somewhat verbose because it fully
qualifies all the called objects using their namespaces, rather than using the Imports statement.
TIP
If you intend to use code generated by the Server Explorer, you should not modify
the generated code because VS .NET uses it to display the appropriate information in
the Properties window and the Component Designer.
Document Outline
When developing HTML, it often comes in handy to view a hierarchical representation of the
HTML contained on the page. The Document Outline window is a holdover from the
VID/VJ++ IDE and displays a nested, hierarchical view of the elements and scripts on a Web
page when either in Design or HTML view. The window is invoked from the View, Other
Windows menu and can be used to navigate through the page when in HTML Outline view or
to add a client-side script when in Script Outline view. Both views are accessible from the tool-
bar within the window. By double-clicking on an element, it is highlighted in the code editor.
Object Browser
VB developers should be familiar with the Object Browser window accessible through the
View, Other Windows menu. As in VB 6.0, by default, it contains three panes and displays
classes and their members for the active project, in addition to projects they reference. At the
highest level, each assembly is displayed with its child namespaces followed by the interfaces
and classes they support in the left-hand pane. The members and their signatures are displayed
in the right-hand pane, whereas links to the online help are found in the bottom pane.
TIP
The Object Browser can be used to copy the fully qualified name of a particular mem-
ber to the Clipboard by right-clicking on it and selecting Copy.
The Development Environment
63
CHAPTER 2
The Object Browser actually contains two browse modes. In addition to displaying information
on the active project, you also can select Selected Components from the drop-down and use
the Customize button to add components that are not referenced in the project. Although the
list of objects changes with each project you click on in the Solution Explorer when in active
project mode, the list of references remains the same and is saved when VS .NET closes when
in Selected Components mode.
Unlike other windows, such as the Toolbox and Server Explorer, the Object Browser window
is not set to dockable by default. Thus, it displays in the list of windows accessible through
tabs, along with the Start page and code editor windows. As is the case for all windows, by 2
right-clicking on the tab for the window or the title bar, the dockable option can be set to allow
DEVELOPMENT
ENVIRONMENT
the window to be docked.
THE
Task List
Like the Document Outline, the Task List window originated in the VID/VJ++ IDE, and can be
used to track the development tasks you must complete. In addition, it can be used to display
compilation errors and warnings. In this way, the Task List often includes a combination of
user-defined and system-defined messages.
NOTE
The dockable Task List window also displays the Command, Output, and Breakpoints
windows accessed using the tabs on the bottom of the window. We will discuss this in
more detail in Chapter 6, “Error Handling and Debugging.”
The left-hand columns of the Task List display the priority along with an icon that shows the
type of message displayed in the description. The full list of types can be found in the online
help. To add a new task, simply click on the first entry in the list and enter the data. User-
defined tasks also allow you to mark when they are complete by using the check box. The
tasks themselves then can be filtered by type and status, in addition to being sorted using the
context menu invoked when you right-click on the window.
One of the more interesting uses of the Task List window is to annotate your code with com-
ments that are automatically loaded as tasks. When the task is clicked on, the code window is
opened and the commented line is navigated to. This feature is controlled through the Options
dialog in the Environment, Task List pane. In this pane, you can add, modify, and delete tokens
that you use as the prefixes for comments. By default, HACK, TODO, UNDONE, and
UnresolvedMergeConflict tokens are defined. Although you cannot delete the TODO token
because it is used by various classes in the framework, you can add your own tokens to, for
example, highlight a particular algorithm for other developers.
.NET Concepts
64
PART I
For example, by creating a custom token called QUILOGY and creating a comment prefixed with
the token and a colon, the description will be added to the Task List, as shown in the following
code:
‘QUILOGY: Authentication code
FormsAuthentication.SetAuthCookie(txtEmail.Text, False)
Dynamic Help
The final major window in the IDE in Figure 2.1 is the Dynamic Help window. The objective
of this window is to display context-sensitive help topics based on the current area or task you
are working with in the IDE. The list of topics is displayed based on the relative weight and is
broken down into categories, such as Help, Actions, Miscellaneous, and Samples.
NOTE
The list of topics shown in this window is not affected by the help filter you can spec-
ify on the Start page.
You can customize which categories and topics, in addition to how many links are displayed in
the window by using the Environment, Dynamic Help panel in the Options dialog.
When you click on a link, it is displayed directly within the IDE in a separate window.
Although some developers might find this feature useful because it displays context-sensitive
help, the sheer amount of screen real estate it entails, coupled with the fact that the help win-
dow tends to get lost, means that many developers will opt for opening the help standalone
using the icon in the Microsoft Visual Studio .NET program group.
DEVELOPMENT
ENVIRONMENT
Used for creating your own classes (that is, business
logic or data access classes).
THE
Module Creates a file with a .vb extension, adds it to the pro-
ject, and includes a Module declaration. As in VB 6.0,
modules are used for utility functions and global
data. Basically, a module is implemented as a class
that contains only shared members and that is not
createable. Any code within the same namespace as
the module can access its members without qualifica-
tion. This is not to be confused with CLR modules,
which were discussed in Chapter 1.
Component class Creates a file with a .vb extension and adds it to the
project with a Class declaration derived from
System.ComponentModel.Component. Allows visual
design of components using the Server Explorer
window.
Transactional component Creates a file with a .vb extension and adds it to the
project with a Class declaration that derives from
System.EnterpriseServices.ServicedComponent.
Can be used as the basis for business logic and data
access components that use COM+ services such as
transactions.
Code file Creates an empty file with a .vb extension.
DataSet Creates a file with a .xsd extension that allows you to
graphically design an XSD schema for a
System.Data.DataSet class. Exposes an autogener-
ated .vb file that represents a strongly typed DataSet.
XML file, XML schema, XSLT Used to create files of these types to be contained in
the project.
.NET Concepts
66
PART I
Windows Forms
When creating a form-based application, which is beyond the scope of this book, you can add
Windows Forms, forms inherited from an existing form (referred to as an inherited form), user
controls, inherited user controls, and custom controls.
DEVELOPMENT
ENVIRONMENT
Crystal report Automatically references the Crystal reports
THE
assemblies and invokes the Crystal Report
Gallery to build a new report with a .rpt exten-
sion to add to the project.
Installer class Creates a file with a .vb extension that contains
a class derived from
System.Configuration.Install.Installer
used to install server-based resources, such as
performance counters and event logs. Also ref-
erences the appropriate assembly.
Assembly resource file Creates a file with a .resx extension used to
house resources used for localization.
Assembly information file Creates a .vb file that contains standard assem-
bly-level attributes used to specify general
information about the assembly, such as the
title, description, and version.
Application configuration file Creates an app.config file in the project used to
store configuration information as discussed in
Chapter 1.
JScript, VBScript, Windows Script host Creates empty files with .js, .vb, and .wsf
extensions, respectively.
By invoking the References dialog from the Project, Add Reference menu, or right-clicking on
references in the Solution Explorer window, the references dialog is displayed, as shown in
Figure 2.4.
FIGURE 2.4
The References dialog allows you to reference assemblies external to your project.
NOTE
You also can add Web references using the Add Web Reference menu option. This is
used to refer to Web Services and will be covered in detail in Chapter 11.
By referencing an assembly, you are including information about it in the manifest of your
assembly, including the specific version you are referencing.
NOTE
As mentioned in Chapter 1 and expounded on in Chapter 5, assemblies can either be
private or shared. Private assemblies are those that do not have a strong name and as
a result are deployed in the application directory. To that end, VS .NET automatically
copies private assemblies to the application directory. This behavior can be controlled
on a per-assembly basis by changing the Copy Local property in the properties win-
dow to False. Note, however, that changing Copy Local to False causes an exception
to be thrown at runtime if classes from that assembly are loaded by your application
and not found.
The Development Environment
69
CHAPTER 2
Obviously, referenced assemblies then will appear in the Object Browser, and you can program
against any of its public types. Because assemblies contain a hierarchy of namespaces, some of
which are nested several levels, referencing a class from an assembly can require a lengthy
statement. For example, if an assembly that contains data access classes for Quilogy is refer-
enced, the required code for accessing the Students class is as follows:
Dim oEnroll As Quilogy.Education.Enrollment.Students
Because typing code like this, even with Intellisense, is unwieldy and hurts readability, you can
use the Imports statement to reference a namespace to allow the names of types to be used
without qualification. For example, the same declaration also could be made like so: 2
Imports Quilogy.Education.Enrollment
DEVELOPMENT
ENVIRONMENT
Dim oStud As Students
THE
Each code file (.vb) can contain multiple Imports statements that must appear at the top of the
file directly after the Option statements, such as Option Strict and Option Explicit.
NOTE
The scope of the names referenced in the Imports statement includes the namespaces
declared within the file. In other words, Imports statements do not span source files.
Because it is certainly possible to reference assemblies that contain types with the same name,
it is sometimes necessary to use an alias to refer to a specific namespace. For example, if both
a client and the Quilogy.Education.Enrollment namespace contained a Students class, the
two could be differentiated in the following manner:
Imports QEnroll = Quilogy.Education.Enrollment
Note that the alias is defined by setting the alias name equal to the name of the namespace.
Macros
In the past, VB developers did not have access to macros, although conceptually they are the
same as the macros you might be familiar with in products, such as Microsoft Excel. As in
those products, macros can be recorded in VS .NET using the macro recorder on the Tools,
Macros menu. The resulting code is contained in a module accessible by viewing the Macro
Explorer window from the Tools, Macros menu. The window appears as an additional pane in
the Solution Explorer window and can be used to edit, delete, run, and add new macros. For
example, by right-clicking on the macro and selecting Edit, the macro IDE opens to allow
editing.
NOTE
Macros are compiled automatically, so you do not have to explicitly compile them in
the macro editor. Simply saving your changes causes the macro to be recompiled the
next time it is executed. If the macros you develop contain intellectual property that
you want to distribute and conceal from third parties, consider implementing the
macro as an Add-In, as discussed in the next section.
Typically, macros are used by a single developer to automate a common set of keystrokes, or to
interject code into the code editor window that would otherwise require more complex manipu-
lation. Macros are saved in the \VSMacros directory under the path found in the Options dialog
in the Environment, Projects and Solutions panel. Macros can be stored as either binary or text
files controlled through the StorageFormat property in the Properties window. Saving the
macro as a binary file enables you to share it more easily, whereas saving it as text allows you
to manipulate it outside VS .NET.
TIP
Macros can include event handling code that runs automatically when the macro is
opened, although not when VS .NET is opened. Because this presents a potential
security concern, event handling can be disabled for all macros using the
DefaultSecurity property in the Properties window when the highest level node in
the Macro Explorer is selected. In addition, event handling can be disabled for specific
collections of macros in the same way.
Although a discussion of the automation object model is beyond the scope of this book, the
code in Listing 2.2 illustrates what can be done with a macro.
The Development Environment
71
CHAPTER 2
TIP
As with any macro recorder, you can use it to explore the automation object model
by recording a number of the actions you typically perform with VS .NET and then
reviewing the generated code. You then can use this code as the basis for new
macros.
LISTING 2.2 Creating a Macro. This listing shows the code to create a macro that inserts 2
a new region around the highlighted text.
DEVELOPMENT
ENVIRONMENT
Imports EnvDTE
Imports System.Diagnostics
THE
Imports Microsoft.VisualBasic.ControlChars
End Module
Listing 2.2 contains the complete code for a macro created by right-clicking on MyMacros in
the Macro Explorer window and choosing New Macro. After renaming the Sub procedure, the
code in the procedure was created to automatically create a collapsible region around any text
currently highlighted in the code editor window.
In Listing 2.2, the automation model is exposed through an assembly called EnvDTE and is
imported using the Imports statement. After prompting for the name of the region using the
InputBox function, the active selection is retrieved in a TextSelection object using the
Selection method of the ActiveDocument object within the highest level object in the automa-
tion model, DTE (Development Tools Extensibility).
The beginning and ending points for the TextSelection then are retrieved by using the
TopPoint and BottomPoint properties. The capability to insert text at these points in the win-
dow is accomplished by creating edit points on each using the CreateEditPoint method.
To make sure that errors that occur while editing the code can be undone, the Open method of
the UndoContext object is invoked. Basically, this is analogous to beginning a transaction
within the IDE, and if an exception is thrown, all changes will be undone. The actual editing of
the code occurs in the Try block (discussed in Chapter 6). The StartOfLine method moves the
insertion point to the beginning of the line indicated in the EditPoint, in this case the starting
point of the TextSelection, and then text is inserted using the Insert method. Similarly, the
#End Region statement is inserted at the end of the selection. The Finally block then issues
the Close of the UndoContext to commit the changes.
To use this macro, you can highlight a block of code and then double-click the macro in the
Macro Explorer window. The result is a new region that contains the highlighted code.
NOTE
For more information on the automation object model, see the online documentation.
Add-Ins
The second way to extend the IDE is through the use of add-ins. Although VB developers
should be familiar with the concept because VB 6.0 exposed an Add-In model, the
The Development Environment
73
CHAPTER 2
programmatic interface is not the same. Add-ins are useful for encapsulating code that you
want to distribute throughout an organization or to third parties. Typically, corporate develop-
ers have more use for macros than for add-ins, so a complete discussion of the topic is beyond
the scope of this book.
In a nutshell, the best way to create an add-in and make sure that it is registered is to use the
Visual Studio .NET Add-In project template found in the Other Projects, Extensibility Projects
folder when creating a new project. The resulting project contains a class called Connect that
includes stubs for the various methods you typically would implement for the add-in. In addi-
tion, it registers the add-in and provides additional instructions. The template also creates a 2
Windows Installer project for packing the add-in with the appropriate dependencies.
DEVELOPMENT
ENVIRONMENT
After the add-in is registered, it can be loaded through the Add-In Manager dialog accessible
THE
from the Tools menu.
Using Attributes
One of the concepts introduced in the CLR, that will be new to many VB developers, is that of
attributes. Basically, attributes are declarative structures that are placed at the assembly, inter-
face, structure, class, or member level, and are typically used to instruct the compiler or com-
ponents of the CLR—such as the security system—how to treat the entity on which the
attribute is placed.
The syntax for using attributes in VB .NET is to enclose the attributes in < > symbols sepa-
rated by commas directly before the declaration of the entity on which the attribute should take
effect. In addition, each attribute can be placed on a separate line for readability. For example,
attributes used by the RegAsm utility that registers a managed assembly as a COM class called
GuidAttribute and ProgIdAttribute can be placed on a class declaration like so:
<GuidAttribute(“A2AD3270-9BB3-4CBA-8206-C87CAA33F562”), _
ProgIdAttribute(“MyAddin1.Connect”)> _
Public Class Connect
Attributes can contain constructors, as shown here, in addition to other public properties. To set
a property not found in the constructor, use the := operator like so:
<ConstructionEnabled(True, Default:=”c:\logfile=da.log”)> _
Public Class DataAccess
In this example, the constructor accepts a Boolean that enables Component Services object
construction, and populates an additional Default property that can be set to a string that spec-
ifies the location of a log file, for example.
In addition to simply using attributes exposed by the framework, you can create your own
attributes to specify custom metadata. For example, if you were designing a set of framework
.NET Concepts
74
PART I
classes to be widely distributed, you could create a custom attribute to encapsulate information
about reference documentation.
To create a custom attribute, you simply need to create a new class that derives from
System.Attribute. Listing 2.3 illustrates creating a custom attribute called
DocumentationAttribute to include documentation information.
NOTE
It is customary to add the suffix “Attribute” to the name of the attribute; however,
clients that use the attribute needn’t include this part of the name.
LISTING 2.3 Creating a Custom Attribute. This class implements a custom attribute for
documentation purposes.
<AttributeUsage(AttributeTargets.Class Or _
AttributeTargets.Interface Or AttributeTargets.Enum Or _
AttributeTargets.Struct)> _
Public Class DocumentationAttribute : Inherits Attribute
End Class
The Development Environment
75
CHAPTER 2
In Listing 2.3, even before the class is declared, it too uses an attribute called AttributeUsage
to control on which types of entities the attribute can be placed. In this case, the Or operator is
used with constants from the AttributeTargets enumeration to indicate that the
DocumentationAttribute can be placed on a class, interface, enumerated type, or structure
only.
TIP
To allow an attribute to be placed anywhere, you can use AttributeTargets.All. The
AttributeUsageAttribute also exposes an AllowMultiple Boolean property that indi- 2
cates whether multiple instances of the attribute can be placed on the same entity.
DEVELOPMENT
ENVIRONMENT
THE
Also notice that this attribute contains two properties, Author and Url, and that Url is passed
to the constructor and is required.
Users of the attribute then can decorate their classes with the DocumentationAttribute as
follows:
<Documentation(“http://www.quilogy.com/qa/dataaccess.aspx”, _
Author:=”Dan Fox”)> _
Public Class QuilogyDataAccess
As noted previously, “Attribute” can be omitted from the declaration, and because the Author
property is not found in the constructor, it can be added to the declaration using the := assign-
ment operator.
At runtime, a client of the class that declared the attribute can read the attribute information
using the GetCustomAttributes method of the Type object. For example, the following code
uses the GetType function to return the Type object for QuilogyDataAccess from the previous
code example:
Dim type As Type = GetType(QuilogyDataAccess)
Dim arr() As Object
Dim att As Attribute
arr = type.GetCustomAttributes(False)
For Each att In arr
If TypeOf att Is DocumentationAttribute Then
Dim da As DocumentationAttribute = _
CType(arr(0), DocumentationAttribute)
Console.WriteLine(“Url = “ & da.Url & “Author = “ & da.Author)
End If
Next
.NET Concepts
76
PART I
It then retrieves an array of custom attributes using the GetCustomAttributes method and
walks through the array looking for the DocumentationAttribute using the TypeOf statement.
When found, it converts the Object to the DocumentationAttribute type so that its properties,
Url and Author, can be queried.
Command-Line Compilation
Although most developers typically use the VS .NET IDE to build their projects, VB .NET also
ships with a command-line compiler, VBC.exe. This can come in handy for automating compi-
lation through batch files, and it contains a complete set of switches to do everything that the
VS .NET build option does.
TIP
A convenient way to use the command-line compiler is to open the Visual Studio .NET
command prompt from the Visual Studio .NET Tools folder installed in the Visual
Studio .NET program group. The command window opens with the appropriate paths
set to access the command-line compilers.
For example, the following command line compiles all the .vb files in the current directory into
a library assembly (/t:target) called EducationData.dll (/out). In addition, debugging informa-
tion is included (/debug), and no logo information is displayed (/nologo), whereas the /r
option references the MyCustom.dll assembly in a manner analogous to setting a project refer-
ence in VS .NET.
vbc /target:library /out:EducatiobData.dll /nologo /debug /r:MyCustom.dll *.vb
The command-line compiler additionally can create standalone modules using the
/target:module option that later can be compiled into multifile assemblies that can include
modules produced in other languages.
As shown in the previous code example, using the command-line compiler entails setting all
the appropriate options for the project, such as references contained in the .vbproj file created
by VS .NET when a project is created. To take advantage of the .vbproj file and still perform a
command-line compile, you can use devenv.exe, the VS .NET IDE, from the command line.
For example, to compile a particular project from within a solution, you could use the follow-
ing command line:
devenv DataAccess.sln /build debug /project EducationDA.vbproj
The Development Environment
77
CHAPTER 2
In this case, the EducationDA project from the DataAccess solution will be built using the
debug configuration. The output written to the console is identical to that typically found in the
Output Window within VS .NET.
Summary
This chapter provided a quick tour of the VS .NET IDE to get you up to speed on how it is
organized and some of its features. Obviously, detailed information on the various options is
best accessed by using the online documentation and especially the dynamic help window as
you use the various features of the IDE. 2
Now that the stage is set, it’s time to begin exploring the particular changes and features of the
DEVELOPMENT
ENVIRONMENT
VB .NET language that will be used in building applications with VB .NET. This is precisely
THE
the subject of the next two chapters.
VB .NET Language Features CHAPTER
3
IN THIS CHAPTER
• Keyword Changes 80
• Functional Changes 85
As is obvious by now, VB .NET and VS .NET contain significant changes from previous versions
of VB in terms of the runtime architecture and the features of the development environment itself.
In addition, the VB .NET language has been changed in accordance with the design goals to
modernize and simplify the language, reduce programming errors, and provide full access to the
Common Language Runtime (CLR) and Services Framework. Although some of these changes
have produced much discussion in the VB community, my personal view is that this is good
because it tightens the language and therefore makes it a better tool for development.
As a result of these changes, the language has actually been simplified in several respects by
removing duplicate or confusing constructs, removing functionality now supported by the
Services Framework, and taking away some of the idiosyncratic behavior particular to BASIC.
In this chapter, we’ll walk through the details of these changes as they related to both the struc-
ture of the language and the functional changes that might require you to think differently
when coding in VB .NET. In addition, we’ll explore the compatibility features that assist in
transitioning code from VB 6.0 to VB .NET including using the Upgrade Wizard. However, it
should be noted that some of the modernizing features that require more in-depth treatment,
such as changes to classes, inheritance, explicit interface declaration, structured exception han-
dling, and free threading, will be handled in Chapter 4, “Object-Oriented Features,” Chapter 6,
“Error Handling and Debugging,” and Chapter 12, “Accessing System Services.”
NOTE
All code listings and supplemental material for this chapter can be found on the
book’s Web site at www.samspublishing.com.
Keyword Changes
Unlike previous versions of VB, VB .NET runs within the context of the CLR and, as a result,
must adhere to the rules of any Common Language Specification (CLS) compliant language. It
shouldn’t be surprising to learn that, as a result, the language itself is contained in an assembly
with the namespace Microsoft.VisualBasic. When you choose to create a project in VS
.NET with VB .NET, this assembly automatically is referenced, and its classes and methods
can be referred to without using dot notation because they are declared with a special attribute
making them global. This means that you don’t have to be concerned with the class structure
of the Microsoft.VisualBasic namespace, although the online documentation breaks it down
for you. For the purposes of this chapter, we’ll treat all the members of the classes contained in
the Microsoft.VisualBasic namespace as peers and intrinsic keywords.
VB .NET Language Features
81
CHAPTER 3
To begin, consider Table 3.1, which shows the keywords removed from VB .NET available in
previous versions. Contrast this table with the keywords added to the language in Table 3.2.
LANGUAGE
VB .NET
FEATURES
property of the System.DateTime structure to
return the day in the 8-byte CLR format.
Debug.Assert, Debug.Print Replaced by methods in the System.Diagnostics
namespace.
DefBool, DefInt, DefStr, and so on Formerly used to specify data types for implicit
declarations. No longer supported.
DoEvents Replaced by a method in the
System.WinForms.Application class.
Empty, Null, IsEmpty, IsNull Formerly used for uninitialized variables and
those that don’t contain data. Now both condi-
tions are handled by Nothing. Statements to
check for these conditions also have been
removed. Database nulls can be tested for using
the IsDBNull function or against the
System.DBNull.Value property.
Eqv, Imp Bitwise operators replaced by the equals (=)
operator and using Not and Or in conjunction
(A Imp B) = ((Not A) Or B).
.NET Concepts
82
PART I
LANGUAGE
VB .NET
FEATURES
replaced with While...End While.
You’ll notice that in most instances for keywords removed from the language, an equivalent
functionality exists in the Services Framework. In addition, many of the new keywords are
related to the object-oriented features of VB .NET provided by the CLR. However, taken as a
whole, you can see that the language has not become more complex through the addition of
scores of keywords.
Functional Changes
In addition to the syntactical changes, VB .NET behaves differently from previous versions in
several respects. This section details the most significant of those changes.
Declarations
Several of the most obvious and productivity-enhancing changes in the language are related to
dimensioning and instantiating variables.
As you might be aware through painful experience, in prior versions, a declaration like so
Dim x,y,z As Integer
did not result in three Integer variables. In fact, the first two variables were declared as 3
Variant, which wastes memory and has the potential of causing type conversion problems
LANGUAGE
down the road. In VB .NET, multiple declarations work as expected, and so the same declara-
VB .NET
FEATURES
tion will result in three Integer variables. In addition, VB .NET supports the capability to use
the declaration
Dim z
when the Option Strict statement is set to Off. In this case, rather than result in a Variant,
the variable z is of type System.Object. Also note that unlike in previous versions, Option
Explicit is defaulted to On so that variables cannot be used without first declaring them.
VB .NET also supports parameterized constructors so that objects can be initialized during the
declaration. This, coupled with support for initialization during declaration, allows VB .NET to
support the following types of syntax:
Dim dtAaron As New DateTime(1974, 4, 8)
Dim strName As String = “Hank Aaron”
Dim arTheropods() As String = {“Tyrannosaur”, “Allosaurus”, “Deinonychus”}
In this example, the dtAaron variable is declared as a DateTime structure and instantiated with
arguments passed to the constructor specifying the day Hank Aaron hit his 715th homerun. This
is shorthand for the statement:
Dim dtAaron As DateTime = New DateTime(1974, 4, 8)
.NET Concepts
86
PART I
In the second example, VB .NET takes care of calling the constructor for the String variable
to allow developers to work with strings in a familiar fashion. The third example shows how to
initialize an array of strings during declaration.
TIP
Although the constants you would expect (those prefixed with “vb”) exist within the
Microsoft.VisualBasic namespace, they also are exposed through enumerated
types. Because the methods of the namespace expect the enumerated types, it is
recommended that you use them rather than the constants.
Object Creation
Two other changes from the behavior of previous versions of VB are related to the creation of
objects using the New operator. In previous versions the statement
Dim dino As New Dinosaur
would result in the compiler actually wrapping each line of code that referenced dino with a
check to see whether the variable was Nothing. If so, the object was instantiated. In VB .NET,
implicit object creation is not supported, and so the object is instantiated when the Dim state-
ment is encountered. As a result, if you’re going to use the New operator in a declaration, you’ll
want to place the declaration within the procedure in a place you know the variable will be
used. In other words, it is more efficient if you defer dimensioning variables that might end up
not being used, as long as possible.
In addition, in VB 6.0, the New operator actually used an internal algorithm that was more effi-
cient to instantiate classes within the same project. In VB .NET, the CLR creates and manages
all object instances, and so there is no difference when New is used with classes in the local
assembly versus a remote assembly.
Finally, the CreateObject function, although still supported, will only be used to create a
COM object. All managed classes are instantiated with the New keyword.
Operators
As shown in Table 3.2, VB .NET adds support for new operators. Perhaps the most significant
from a keystroke-saving perspective are the operators that perform their operation and assign
the result to the variable. For example, in VB 6.0, to concatenate a string on two lines, you
would do the following:
Dim strMessage As String
does not assign the string variable strName to the Text property of the Text1 object. As a
result, you must explicitly use the property. The good news is that this means the Set and Let
statements, which caused a good deal of confusion, are no longer required or supported. The
one exception to default properties is in the case where the property accepts a parameter. In
this instance, you can mark the property as the default so that working with objects that sup-
port collections through properties such as Item is simplified.
Operators evaluation in expressions also can be short-circuited in VB .NET so that a procedure
like the one that follows can be more efficient:
3
Sub Insert(ByVal value As Integer, ByVal sortedArr() As Integer)
Dim intIndex, intIndxSrch As Integer
LANGUAGE
VB .NET
FEATURES
Dim intArrCount As Integer = sortedArr.Length
In this example, the Insert procedure inserts a new value in a sorted array. Note that the
While loop contains the new AndAlso operator with two expressions. Using short-circuit evalu-
ation, the second condition, which is the more expensive of the two, will not be executed if the
first condition returns False. In the past, you needed to place these conditions on separate lines
to gain this efficiency. Short-circuiting also is implemented with the new OrElse operator
when the first expression evaluates to True.
NOTE
Although it was originally planned that the And, Or, Not, and Xor operators would
only perform logical and not bitwise operations, feedback from the VB community
ensured that these retain both functionalities and precedence rules as in VB 6.0.
.NET Concepts
88
PART I
Although not documented in VB 6.0, some developers became accustomed to using the
VarPtr, VarPtrArray, VarPtrStringArray, ObjPtr, and StrPtr operators to return the
memory addresses of variables of these data types. This was particularly useful when calling
some Win32 API functions. These keywords are no longer supported in VB .NET.
Closely related to operators is the behavior of null values. In VB 6.0, null propagation was sup-
ported where adding or concatenating a value to Null, or a Variant that contained Null,
always produced a null value. In VB .NET, Null has been replaced with Nothing, Variant
with Object, and null propagation is not supported. As a result, the following behavior occurs
in VB .NET when Option Strict is set to Off:
Dim x As Object
Dim i As Integer
i = 4
x = Nothing
i = i + x ‘ i still equals 4
The Null keyword has been replaced with the System.DBNull class, and checking for nulls
returned from databases can be done using the IsDBNull function. The equivalent syntax used
in VB 6.0, where an empty string (“”) concatenated to a null from a database produced an
empty string, is still supported as well.
The absence of both variants and null values implies that functions that once accepted variants
and possibly returned null values, such as Mid, Oct, Right, RTrim, Space, Str, Time, Trim,
LTrim, UCase, and LCase, among others, now simply return their associated data types. As
mentioned in Table 3.1, VB 6.0 also contained companion functions appended with $ (i.e.
Trim$) that returned String values. These also have been replaced with overloaded methods
that return a String.
Data Types
As discussed in Chapter 1, “The Microsoft .NET Architecture,” all data types in VB .NET
derive from System.Object and are therefore a part of the Common Type System (CTS) used
by the CLR. VB .NET supports keywords that map to the CTS types shown in Table 1.1. This
mapping is shown in Table 3.3.
As in VB 6.0, the type character can be used to automatically dimension a variable by append-
ing it to the declaration. For example,
Dim z%
3
ensures that z is an Integer. However, because type characters make the code less readable,
they are not recommended.
LANGUAGE
VB .NET
FEATURES
In addition, several of the data types include special characters (literal type characters) that can
be used with literal values to force their representation to the appropriate type. These include
C (Char), D (Decimal), R (Double), I (Integer), L (Long), S (Short), and F (Single). In other
words, the statement
Dim b As Object
b = “T”C
The internal representation of several data types in the CLR also is different from previous ver-
sions of VB. For example, the Boolean data type in VB 6.0 equated to -1 for True and 0 for
False. Now, the more standard 0 for False and 1 for True is used by the runtime. However, to
maintain backwards compatibility when working in VB .NET, the older -1 and 0 will be used.
Keep in mind, though, that converting a Boolean to a CTS type such as System.Int32, or pass-
ing a Boolean to another managed language, will convert the result back to a 1 for True and 0
for False. Also, as mentioned in Table 3.3, the Date data type is no longer represented as a
Double; it is mapped to System.DateTime, and implicit conversion between the two is no
longer supported. Explicit conversion, however, can be accomplished by using the ToDouble
and FromOADate methods of the DateTime class.
Of course, as should be obvious by now, the universal data type in previous versions of VB, the
Variant, has been replaced with Object. The Object keyword used in VB 6.0 to refer to a late
bound object has been subsumed into this definition.
Finally, as shown in Table 3.1 the Currency data type is no longer supported in VB .NET and
has been replaced with the Decimal data type.
Arrays
There are several important changes in VB .NET with regards to arrays. First, the lower bound
of an array can no longer be set using the Option Base statement. As a result, the syntax
Dim s(0 to 10) As String
NOTE
The designers of VB .NET originally planned that the array declaration would specify
the number of elements and not the upper bound. In other words, the declaration
Dim s(10) As String
would produce an array of 10 elements with indices from 0 through 9. However, this
changed shortly before the beta 2 was released based on feedback from the VB
community.
Also in VB .NET, by default, all arrays are variable-sized arrays, so they all can be resized
using the ReDim statement. However, the ReDim statement cannot be used in place of the Dim
statement to dimension an array as in VB 6.0.
VB .NET Language Features
91
CHAPTER 3
In addition, as seen previously, an array can be populated in the declaration using the { }
brackets like so:
Dim sosaHomers() As Short = {66, 63, 50, 64}
This syntax replaces the Array function formerly used to populate an array with arguments
passed to the function. VB .NET still supports multidimensional arrays; however, the number
of dimensions (referred to as the rank) must be set in the Dim statement. For example, the code
Dim arPlayers(,) As String
ReDim arPlayers(1, 3)
arPlayers(0, 0) = “Pitcher”
arPlayers(0, 1) = “Catcher”
arPlayers(0, 2) = “1B”
arPlayers(0, 3) = “2B”
LANGUAGE
VB .NET
FEATURES
VB .NET also allows you to change the upper bound of the last dimension in the array while
preserving the contents of the array, and so the statement
ReDim Preserve arPlayers(1, 4)
immediately after the preceding code example successfully adds another element to the second
dimension. The Preserve keyword ensures that the data is preserved.
TIP
As in VB 6.0, if you don’t know the rank the array will have at development time,
then dimension the array simply As Array or As Object.
VB .NET also still supports ragged arrays or arrays of arrays, which, like multidimensional
arrays, allow you to store tabular type data but allow a varying number of elements. For exam-
ple, the code in Listing 3.1 shows how you would create a ragged array by dimensioning the
array As Object and then placing arrays inside it.
.NET Concepts
92
PART I
LISTING 3.1 Creating Ragged Arrays in VB .NET. To create a ragged array use the
Object type.
Dim a As Object
Dim b(0) As String
Dim c(1) As String
Dim obj As Object
Dim obj1 As Object
ReDim a(2)
Note that Option Strict must be set to Off for this code to compile because late binding is
occurring in the array referenced as a. Although this works in VB .NET, you might want to
stick with multidimensional arrays because ragged arrays are not CLS compliant, and passing
such an array to managed code written in another language might not work.
Many of these changes are made possible by the fact that all arrays in VB .NET are ultimately
derived from System.Array. This class supports several shared methods that can be used to
manipulate arrays as well as instance methods that can return data on a particular array. As you
would expect, because System.Array is a reference type, assigning a variable to an existing
array creates a reference to the array rather than a copy of it. To get a copy, you can use the
Clone method of the Array class.
VB .NET Language Features
93
CHAPTER 3
TIP
Shared methods can be called on a class without first instantiating an object from the
class. This allows the class to contain various helper functions that can be used in a
variety of situations. Conversely, instance methods are those that work on the current
instance of the class.
For example, the declaration of the arPlayers array in VB .NET is actually translated to this:
Dim arPlayers As Array
arPlayers = Array.CreateInstance(GetType(String), 2, 4)
Note that the sizes of the dimensions as specified in the last two arguments to the CreateInstance
method are set to 2 and 4, rather than 1 and 3 as you might expect. This is the case because
arrays in the CLR typically are declared using the size of a dimension rather than the upper
bound.
Even if the array is created in standard VB .NET syntax, all the Array methods and properties 3
are available, the most important of which are shown in Table 3.4.
LANGUAGE
VB .NET
FEATURES
TABLE 3.4 Array Class Members
Member Description
BinarySearch Shared method that searches a one-dimensional array for a spe-
cific element
Clear Shared method that sets a range of the array to zero or Nothing
Copy Shared method that copies a section of one array to another array
CreateInstance Shared method that initializes a new instance of the Array class
IndexOf Shared method that returns the index of the first occurrence of a
given value in a one-dimensional array
LastIndexOf Shared method that returns the last index of the first occurrence of
a given value in a one-dimensional array
Reverse Shared method that reverses the order of elements in a one-dimen-
sional array
Sort Shared method that sorts the elements of a one-dimensional array
IsFixedSize Instance property that returns True if the array is fixed size
IsReadOnly Instance property that returns whether the array is read-only
IsSynchronized Instance property that returns whether access to the array is
thread-safe
.NET Concepts
94
PART I
To illustrate the use of the Array class, consider the procedure in Listing 3.2 used to find a spe-
cific item in an array.
LISTING 3.2 Using the Array Class. This method exercises some of the functionality of the
Array class to sort and search the array.
Try
VB .NET Language Features
95
CHAPTER 3
End Function
3
In this example, note that the FindVal procedure accepts an argument declared As Object to
search for in the array, along with the array, and returns the index at which the value was
LANGUAGE
VB .NET
FEATURES
found. The new IsArray function is used to determine whether the array has been initialized.
If so, the array is first sorted using the Sort method and then a binary search is performed
using BinarySearch. The return value from BinarySearch will be negative if the value is not
found. Note that by definition, the BinarySearch method is case sensitive. In this case, the
method returns the index of the element if the value is found, and a -1 if not. Since the array is
passed to the method by reference, the array will be sorted when the method returns and the
index will point to the new position of the value within the sorted array.
NOTE
Many of the methods of the Array class work only with one-dimensional arrays. If
you attempt to call these methods on multidimensional arrays, exceptions will be
thrown. To work with, sort, and search multidimensional arrays, you’ll need to
employ your own techniques. Some of these can be found in Chapter 24 of my book
Pure Visual Basic.
Alternatives to Arrays
Although arrays in VB .NET are easily mapped to the System.Array type, they are not always
ideal for manipulating data within your application. To provide more choice and flexibility in
.NET Concepts
96
PART I
working with collections of data, the Services Framework includes the System.Collections
and System.Collections.Specialized namespaces. In fact, using these prebuilt collections
can offload some of the array manipulation code you would normally write and can greatly
improve performance—for example, when needing random access to an in-memory collection
of data.
You can think of these namespaces as containing prebuilt data structures for handling data. For
example, the System.Collections namespace contains the SortedList class that can be used
to store a collection of values and associated keys. As the name implies, the data added to the
collection is sorted automatically by the key, and the class contains various methods to access
the data either by the key, index, or value. The following code illustrates the use of the
SortedList class to store a collection of names:
For i = 0 To employees.Count - 1
Console.WriteLine(“{0}:{1}”, _
employees.GetByIndex(i).ToString, employees.GetKey(i).ToString)
Next
When the For loop is executed, the names are printed in order by their key value.
NOTE
Many of the collection classes include constructors that accept the initial capacity of
the collection. Although the capacity of the collection is increased automatically as
required through reallocation, this can be used to increase performance when you
know ahead of time how many members the collection will contain. In the ArrayList
and SortedList classes, the TrimToSize method can subsequently be called to mini-
mize a lists memory overhead.
Although explicating all the classes and their members is beyond the scope of this book, the
other types of collections, their descriptions, and uses can be seen in Table 3.5.
VB .NET Language Features
97
CHAPTER 3
LANGUAGE
value pairs than 10 values and
VB .NET
FEATURES
need access to them by
the key
NameValueCollection Implements a sorted collection of When you need access
String keys and values to the values by the
hash code of the key or
the index
Queue Implements a first-in, first-out When you need to
collection of objects access the values in
FIFO order
SortedList Implements a collection of key- When you need to
value pairs sorted by the key access the values in
order by the key
Stack Implements a last-in, first-out When you need to
collection objects access the values in
LIFO order
.NET Concepts
98
PART I