BUY THIS BOOK

Safari Books Online

What is this?

Looking to Reprint this content?


.NET Framework Essentials
.NET Framework Essentials, Second Edition By Thuan L. Thai, Hoang Lam
February 2002
Pages: 320

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: .NET Overview
Microsoft announced the .NET intitiative in July 2000. The .NET platform is a new development framework with a new programming interface to Windows services and APIs, integrating a number of technologies that emerged from Microsoft during the late 1990s. Incorporated into .NET are COM+ component services; the ASP web development framework; a commitment to XML and object-oriented design; support for new web services protocols such as SOAP, WSDL, and UDDI; and a focus on the Internet.
The platform consists of four separate product groups:
Development tools
A set of languages, including C# and VB.NET; a set of development tools, including Visual Studio.NET; a comprehensive class library for building web services and web and Windows applications; as well as the Common Language Runtime to execute objects built within this framework.
Specialized servers
A set of .NET Enterprise Servers, formerly known as SQL Server 2000, Exchange 2000, BizTalk 2000, and so on, that provide specialized functionality for relational data storage, email, and B2B commerce.
Web services
An offering of commercial web services, specifically the .NET My Services initiative (formerly called HailStorm); for a fee, developers can use these services in building applications that require knowledge of user identity.
Devices
New .NET-enabled non-PC devices, from cell phones to game boxes.
Microsoft is devoting considerable resources to the development and success of .NET and related technologies: their bets are on .NET as the next big thing in computing.
Microsoft has spent the last four years creating Microsoft .NET, which was publicly launched at PDC 2000 in Orlando, Florida. While the main strategy of .NET is to enable software as a service, .NET is much more than that. Aside from embracing the Web, Microsoft .NET acknowledges and responds to the following trends within the software industry today:
Distributed computing
Simplifies the development of robust client/server applications. Current distributed technologies require high vendor-affinity and lack interoperation with the Web. Microsoft .NET provides a remoting architecture that exploits open Internet standards, including the Hypertext Transfer Protocol (HTTP), Extensible Markup Language (XML), and Simple Object Access Protocol (SOAP).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Microsoft .NET
Microsoft has spent the last four years creating Microsoft .NET, which was publicly launched at PDC 2000 in Orlando, Florida. While the main strategy of .NET is to enable software as a service, .NET is much more than that. Aside from embracing the Web, Microsoft .NET acknowledges and responds to the following trends within the software industry today:
Distributed computing
Simplifies the development of robust client/server applications. Current distributed technologies require high vendor-affinity and lack interoperation with the Web. Microsoft .NET provides a remoting architecture that exploits open Internet standards, including the Hypertext Transfer Protocol (HTTP), Extensible Markup Language (XML), and Simple Object Access Protocol (SOAP).
Componentization
Simplifies the integration of software components developed by different vendors. The Component Object Model (COM) has brought reality to software plug-and-play, but COM component development and deployment are too complex. Microsoft .NET provides a simpler way to build and deploy components.
Enterprise services
Allow the development of scalable enterprise applications without writing code to manage transactions, security, or pooling. Microsoft .NET continues to support enterprise services, since these services greatly reduce the development time and effort involved in building large-scale applications.
Web paradigm shifts
Represents changes in web technologies to simplify the development of web applications. Over the last few years, web application development has shifted from connectivity (TCP/IP), to presentation (HTML), to programmability (XML and SOAP). A key goal of Microsoft .NET is to enable software to be sold and distributed as a service.
Maturity factors
Represents lessons that the software industry has learned from developing large-scale enterprise and web applications. A commercial web application must support interoperability, scalability, availability, and manageability. Microsoft .NET facilitates all these goals.
Although these are the main concepts that Microsoft .NET incorporates, what's more notable is that Microsoft .NET uses open Internet standards (HTTP, XML, and SOAP) at its core to transmit an object from one machine to another across the Internet. In fact, there is bidirectional mapping between XML and objects in .NET. For example, a class can be expressed as an XML Schema Definition (XSD); an object can be converted to and from an XML buffer; a method can be specified using an XML format called Web Services Description Language (WSDL); and an invocation (method call) can be expressed using an XML format called SOAP.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The .NET Platform
The Microsoft .NET Platform consists of five main components, as shown in Figure 1-1. At the lowest layer lies the operating system (OS), which can be one of a variety of Windows platforms, including Windows XP, Windows 2000, Windows Me, and Windows CE. As part of the .NET strategy, Microsoft has promised to deliver more .NET device software to facilitate a new generation of smart devices.
Figure 1-1: The Microsoft .NET platform
On top of the operating system is a series of .NET Enterprise Server products that shortens the time required to develop large-scale business systems. These server products include Application Center 2000, BizTalk Server 2000, Commerce Server 2000, Exchange Server 2000, Host Integration Server 2000, Internet Security and Acceleration Server 2000, and SQL Server 2000.
Since Web Services are highly reusable across the Web, Microsoft plans to provide a number of building-block services that applications developers can use, for a fee. An example of building-block service is Microsoft Passport, which allows you to use a single username and password at all web sites that support Passport authentication. In March 2001, Microsoft announced another set of Web Services with the codename HailStorm, now called .NET My Services. This product encompasses a set of building-block services that support personalization, centered entirely on consistent user experiences. Microsoft plans to add newer services, such as calendar, directory, and search services. Third-party vendors are also creating new Web Services of their own.
At the top layer of the .NET architecture is a brand new development tool called Visual Studio.NET (VS.NET), which makes possible the rapid development of Web Services and other applications. A successor of Microsoft Visual Studio 6.0, VS.NET is an Integrated Development Environment (IDE) that supports four different languages and features such as cross-language debugging and the XML Schema Editor.
And at the center of .NET is the Microsoft .NET Framework—the main focus of this book. The .NET Framework is a new development and runtime infrastructure that will change the development of business applications on the Windows platform. It includes the Common Language Runtime (CLR) and a common framework of classes that can be used by all .NET languages.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
.NET Framework Design Goals
Inherent within the Microsoft .NET Framework are many design goals that are practical yet extremely ambitious. In this section, we discuss the main design goals of the Microsoft .NET Framework, including better support for components, language integration, application interoperation across cyberspace, simple development and deployment, better reliability, and greater security.
Prior to the existence of COM technology, Microsoft developers had no simple way to integrate binary libraries without referring to or altering their source code. With the advent of COM, programmers were able to integrate binary components into their applications, similar to the way we plug-and-play hardware components into our desktop PCs. Although COM was great, the grungy details of COM gave developers and administrators many headaches.
While COM permits you to integrate binary components developed using any language, it does require you to obey the COM identity, lifetime, and binary layout rules. You must also write the plumbing code that is required to create a COM component, such as DllGetClassObject, CoRegisterClassObject, and others.
Realizing that these requirements result in frequent rewrites of similar code, .NET sets out to remove them. In the .NET world, all classes are ready to be reused at the binary level. You don't have to write extra plumbing code to support componentization in the .NET Framework. You simply write a .NET class, which then becomes a part of an assembly (to be discussed in Chapter 2), and supports plug-and-play.
In addition to providing a framework to make development easier, .NET removes the pain of developing COM components. Specifically, .NET removes the use of the registry for component registration and eliminates the requirements for extraneous plumbing code found in all COM components, including code to support IUnknown, class factories, component lifetime, registration, dynamic binding, and others.
"Component" is a nasty word because one person may use it to refer to an object and another may use it to refer to a binary module. To be consistent, this book uses the term "COM component" (or simply "component") to refer to a binary module, such as a DLL or an EXE.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
.NET Framework
Now that you are familiar with the major goals of the .NET Framework, let's briefly examine its architecture. As you can see in Figure 1-2, the .NET Framework sits on top of the operating system, which can be a few different flavors of Windows, and consists of a number of components. (Each of these components is discussed in greater detail starting with Chapter 4, as described in the Preface.) .NET is essentially a system application that runs on Windows.
Figure 1-2: The .NET Framework
The most important component of the Framework is something called the CLR. If you are a Java programmer, think of the CLR as the .NET equivalent of the Java Virtual Machine (JVM). If you don't know Java, think of the CLR as the heart and soul of the .NET architecture. At a high level, the CLR activates objects, performs security checks on them, lays them out in memory, executes them, and garbage-collects them.
Conceptually, the CLR and the JVM are similar in that they are both runtime infrastructures that abstract the underlying platform differences. However, while the JVM currently supports only the Java language, the CLR supports all languages that can be represented in the Common Intermediate Language (CIL). The JVM executes bytecode, so it could technically support many different languages, too. Unlike Java's bytecode, though, IL is never interpreted. Another conceptual difference between the two infrastructures is that Java code runs on multiple platforms with a JVM, whereas .NET code runs only on the Windows platforms with the CLR (at the time of this writing). Microsoft has submitted the Common Language Infrastructure (CLI), which is functional a subset of the CLR, to ECMA, so a third-party vendor could theoretically implement a CLR for a platform other than Windows. For more information on third-party vendors, see Appendix A.
In Figure 1-2, the layer on top of the CLR is a set of framework base classes. This set of classes is similar to the set of classes in STL, MFC, ATL, or Java. These classes support rudimentary input and output functionality, string manipulation, security management, network communications, thread management, text management, reflection functionality, and collections functionality, as well as other functions.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: The Common Language Runtime
The most important component of the .NET Framework is the Common Language Runtime (CLR). The CLR manages and executes code written in .NET languages and is the basis of the .NET architecture, similar to the Java Virtual Machine. The CLR activates objects, performs security checks on them, lays them out in memory, executes them, and garbage-collects them.
In this chapter, we describe the CLR environment, executables (with examples in several languages), metadata, assemblies, manifests, the CTS, and the CLS.
The CLR is the underlying .NET infrastructure. Its facilities cover all the goals that we spelled out in Chapter 1. Unlike software libraries such as MFC or ATL, the CLR is built from a clean slate. The CLR manages the execution of code in the .NET Framework.
An assembly is the basic unit of deployment and versioning, consisting of a manifest, a set of one or more modules, and an optional set of resources.
Figure 2-1 shows the two portions of the .NET environment, with the bottom portion representing the CLR and the top portion representing the CLR executables or Portable Executable (PE) files, which are .NET assemblies or units of deployment. The CLR is the runtime engine that loads required classes, performs just-in-time compilation on needed methods, enforces security checks, and accomplishes a bunch of other runtime functionalities. The CLR executables shown in Figure 2-1 are either EXE or DLL files that consist mostly of metadata and code.
Figure 2-1: The CLR environment
Microsoft .NET executables are different from typical Windows executables in that they carry not only code and data, but also metadata (see Section 2.3 and Section 2.5 later in this chapter). In this section, we start off with the code for several .NET applications, and discuss the .NET PE format.
Let's start off by examining a simple Hello, World application written in Managed C++, a Microsoft .NET extension to the C++ language. Managed C++ includes a number of new .NET-specific keywords that permit C++ programs to take advantage of .NET's new features, including garbage collection. Here's the Managed C++ version of our program:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
CLR Environment
The CLR is the underlying .NET infrastructure. Its facilities cover all the goals that we spelled out in Chapter 1. Unlike software libraries such as MFC or ATL, the CLR is built from a clean slate. The CLR manages the execution of code in the .NET Framework.
An assembly is the basic unit of deployment and versioning, consisting of a manifest, a set of one or more modules, and an optional set of resources.
Figure 2-1 shows the two portions of the .NET environment, with the bottom portion representing the CLR and the top portion representing the CLR executables or Portable Executable (PE) files, which are .NET assemblies or units of deployment. The CLR is the runtime engine that loads required classes, performs just-in-time compilation on needed methods, enforces security checks, and accomplishes a bunch of other runtime functionalities. The CLR executables shown in Figure 2-1 are either EXE or DLL files that consist mostly of metadata and code.
Figure 2-1: The CLR environment
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
CLR Executables
Microsoft .NET executables are different from typical Windows executables in that they carry not only code and data, but also metadata (see Section 2.3 and Section 2.5 later in this chapter). In this section, we start off with the code for several .NET applications, and discuss the .NET PE format.
Let's start off by examining a simple Hello, World application written in Managed C++, a Microsoft .NET extension to the C++ language. Managed C++ includes a number of new .NET-specific keywords that permit C++ programs to take advantage of .NET's new features, including garbage collection. Here's the Managed C++ version of our program:
               #using <mscorlib.dll>
using namespace System;

void main(  )
{
  Console::WriteLine(L"C++ Hello, World!");
}
As you can see, this is a simple C++ program with an additional directive, #using (shown in bold). If you have worked with the Microsoft Visual C++ compiler support features for COM, you may be familiar with the #import directive. While #import reverse-engineers type information to generate wrapper classes for COM interfaces, #using makes all types accessible from the specified DLL, similar to a #include directive in C or C++. However, unlike #include, which imports C or C++ types, #using imports types for any .NET assembly, written in any .NET language.
The one and only statement within the main( ) method is self-explanatory—it means that we are invoking a static or class-level method, WriteLine( ), on the Console class. The L that prefixes the literal string tells the C++ compiler to convert the literal into a Unicode string. You may have already guessed that the Console class is a type hosted by mscorlib.dll, and it takes one string parameter.
One thing that you should also notice is that this code signals to the compiler that we're using the types in the System namespace, as indicated by the using namespace statement. This allows us to refer to Console instead of having to fully qualify this class as System::Console.
Given this simple program, compile it using the new C++ command-line compiler shipped with the .NET SDK:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Metadata
Metadata is machine-readable information about a resource, or "data about data." Such information might include details on content, format, size, or other characteristics of a data source. In .NET, metadata includes type definitions, version information, external assembly references, and other standardized information.
In order for two systems, components, or objects to interoperate with one another, at least one must know something about the other. In COM, this "something" is an interface specification, which is implemented by a component provider and used by its consumers. The interface specification contains method prototypes with full signatures, including the type definitions for all parameters and return types.
Only C/C++ developers were able to readily modify or use Interface Definition Language (IDL) type definitions—not so for VB or other developers, and more importantly, not for tools or middleware. So Microsoft invented something other than IDL that everyone could use, called a type library. In COM, type libraries allow a development environment or tool to read, reverse engineer, and create wrapper classes that are most appropriate and convenient for the target developer. Type libraries also allow runtime engines, such as the VB, COM, MTS, or COM+ runtime, to inspect types at runtime and provide the necessary plumbing or intermediary support for applications to use them. For example, type libraries support dynamic invocation and allow the COM runtime to provide universal marshaling for cross-context invocations.
Type libraries are extremely rich in COM, but many developers criticize them for their lack of standardization. The .NET team invented a new mechanism for capturing type information. Instead of using the term "type library," we call such type information metadata in .NET.
Just as type libraries are C++ header files on steroids, metadata is a type library on steroids. In .NET, metadata is a common mechanism or dialect that the .NET runtime, compilers, and tools can all use. Microsoft .NET uses metadata to describe all types that are used and exposed by a particular .NET assembly. In this sense, metadata describes an assembly in detail, including descriptions of its identity (a combination of an assembly name, version, culture, and public key), the types that it references, the types that it exports, and the security requirements for execution. Much richer than a type library, metadata includes descriptions of an assembly and modules, classes, interfaces, methods, properties, fields, events, global methods, and so forth.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Assemblies and Manifests
As we just saw, types must expose their metadata to allow tools and programs to access them and benefit from their services. Metadata for types alone is not enough. To simplify software plug-and-play and configuration or installation of the component or software, we also need metadata about the component that hosts the types. Now we'll talk about .NET assemblies (deployable units) and manifests (the metadata that describes the assemblies).
During the COM era, Microsoft documentation inconsistently used the term component to mean a COM class or a COM module (DLLs or EXEs), often forcing readers or developers to consider the context of the term each time they encountered it. In .NET, Microsoft has addressed this confusion by introducing a new concept, assembly, which is a software component that supports plug-and-play, much like a hardware component. Theoretically, a .NET assembly is approximately equivalent to a COM module. In practice, an assembly can contain or refer to a number of types and physical files (including bitmap files, .NET PE files, and so forth) that are needed at runtime for successful execution. In addition to hosting IL code, an assembly is a basic unit of versioning, deployment, security management, side-by-side execution, sharing, and reuse, as we discuss next.
To review: an assembly is a logical DLL or EXE, and a manifest is a detailed description (metadata) of an assembly, including its version, what other assemblies it uses, and so on.
Type uniqueness is important in RPC, COM, and .NET. Given the vast number of GUIDs in COM (application, library, class, and interface identifiers), development and deployment can be tedious because you must use these magic numbers in your code and elsewhere all the time. In .NET, you refer to a specific type by its readable name and its namespace. Since a readable name and its namespace are not enough to be globally unique, .NET guarantees uniqueness by using unique public/private key pairs. All assemblies that are shared (called shared assemblies
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Intermediate Language (IL)
In software engineering, the concept of abstraction is extremely important. We often use abstraction to hide the complexity of system or application services, providing instead a simple interface to the consumer. As long as we can keep the interface the same, we can change the hideous internals, and different consumers can use the same interface.
In language advances, scientists introduced different incarnations of language-abstraction layers, such as p-code and bytecode. Produced by the Pascal-P compiler, p-code is an intermediate language that supports procedural programming. Generated by Java compilers, bytecode is an intermediate language that supports object-oriented programming. Bytecode is a language abstraction that allows Java code to run on different operating platforms, as long as the platforms have a Java Virtual Machine (JVM) to execute bytecode.
Microsoft calls its own language-abstraction layer the Common Intermediate Language (CIL). Similar to bytecode, IL supports all object-oriented features, including data abstraction, inheritance, polymorphism, and useful concepts such as exceptions and events. In addition to these features, IL supports other concepts, such as properties, fields, and enumeration. Any .NET language may be converted into IL, so .NET supports multiple languages and perhaps multiple platforms in the future (as long as the target platforms have a CLR).
Shipped with the .NET SDK, Partition III CIL.doc describes the important IL instructions that language compilers should use. In addition to this specification, the .NET SDK includes another important document, Partition II Metadata.doc. Both of these documents are intended for developers who write compilers and tools, but you should read them to further understand how IL fits into .NET. While you can develop a valid .NET assembly using the supported IL instructions and features, you'll find IL to be very tedious because the instructions are a bit cryptic. However, should you decide to write pure IL code, you could use the IL Assembler (
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The CTS and CLS
Having seen the importance of metadata and IL, let's examine the CTS and the CLS. Both the CTS and the CLS ensure language compatibility, interoperability, and integration.
Because .NET treats all languages as equal, a class written in C# should be equivalent to a class written in VB.NET, and an interface defined in Managed C++ should be exactly the same as one that is specified in managed COBOL. Languages must agree on the meanings of these concepts before they can integrate with one another. In order to make language integration a reality, Microsoft has specified a common type system to which every .NET language must abide. In this section, we outline the common types that have the same conceptual semantics in every .NET language. Microsoft .NET supports a rich set of types, but we limit our discussion to the important ones, including value types, reference types, classes, interfaces, and delegates.

Section 2.6.1.1: Value types

In general, the CLR supports two different types: value types and reference types. Value types represent values allocated on the stack. They cannot be null and must always contain some data. When value types are passed into a function, they are passed by value, meaning that a copy of the value is made prior to function execution. This implies that the original value won't change, no matter what happens to the copy during the function call. Since intrinsic types are small in size and don't consume much memory, the resource cost of making a copy is negligible and outweighs the performance drawbacks of object management and garbage collection. Value types include primitives, structures, and enumerations; examples are shown in the following C# code listing:
int i;                     // primitive
struct Point { int x, y; } // structure
enum State { Off, On }     // enumeration
You can also create a value type by deriving a class from System.ValueType. One thing to note is that a value type is sealed, meaning that once you have derived a class from System.ValueType, no one else can derive from your class.

Section 2.6.1.2: Reference types

Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
CLR Execution
Now that you understand the elements of a .NET executable, let's talk about the services that the CLR provides to support management and execution of .NET assemblies. There are many fascinating components in the CLR, but for brevity, we will limit our discussions to just the major components, as shown in Figure 2-4.
Figure 2-4: Major CLR components: the Virtual Execution System (VES)
The major components of the CLR include the class loader, verifier, JIT compilers, and other execution support, such as code management, security management, garbage collection, exception management, debug management, marshaling management, thread management, and so on. As you can see from Figure 2-4, your .NET PE files layer on top of the CLR and execute within the CLR's Virtual Execution System (VES), which hosts the major components of the runtime. Your .NET PE files will have to go through the class loader, the type verifier, the JIT compilers, and other execution support components before they will execute.
When you run a standard Windows application, the OS loader loads it before it can execute. At the time of this writing, the default loaders in the existing Windows operating systems, such as Windows 98, Windows Me, Windows 2000, and so forth, recognize only the standard Windows PE files. As a result, Microsoft has provided an updated OS loader for each of these operating systems that support the .NET runtime. The updated OS loaders know the .NET PE file format and can handle the file appropriately.
When you run a .NET application on one of these systems that have an updated OS loader, the OS loader recognizes the .NET application and thus passes control to the CLR. The CLR then finds the entry point, which is typically Main( ), and executes it to jump-start the application. But before Main( ) can execute, the class loader must find the class that exposes Main( ) and load the class. In addition, when Main( ) instantiates an object of a specific class, the class loader also kicks in. In short, the class loader performs its magic the first time a type is referenced.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
As you can see from this chapter, the .NET architecture strives to support language integration and componentization in every way that makes sense. Thanks to metadata, programming becomes much easier because you no longer have to worry about the registry for component deployment and other kinks (such as CoCreateInstanceEx, CLSIDs, IIDs, IUnknown, IDL, and so forth) in order to support componentization. Thanks to the CTS, CLS, metadata, and IL, you now have real language integration. Microsoft has shipped a CLR for several flavors of Windows, but is also working on a shared-source version of the CLR that will run on FreeBSD and will no doubt be portable to other Unix-like systems. Non-Microsoft implementations of the CLR have also appeared, including DotGNU Portable.NET (for more information, see http://www.southern-storm.com.au/portable_net.html) and Mono (see http://www.go-mono.com). .NET is thus a multilanguage and multiplatform architecture.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: .NET Programming
Now that you know what .NET is all about, let's talk about programming for the .NET environment. This chapter presents the common programming model that .NET provides, core languages and features that .NET supports, and language integration—how you can take advantage of object-oriented features even across different languages that .NET enables.
Without the .NET Framework, programmers must choose from amongst a wealth of APIs or libraries that support system services. For example, if you want to write GUI applications on Windows, you have a slew of options from which to choose, including the Win32 API, MFC, ATL, VB, and so on. Once you've chosen the library, you have to learn how to use the structures, classes, functions, interfaces, and so forth that the library provides. Unfortunately, this knowledge doesn't transfer directly into a different environment. For instance, there's a big difference between the code to manage IO in MFC and the code to manage IO in VB.
One of the goals of the .NET Framework is to bring commonality to application development by providing a framework of common classes to developers who are using compilers that generate IL. This common framework is extremely helpful: if you know how to take advantage of IO functionality in .NET using your favorite language, you can easily port that code to another language. This is possible because the namespaces, classes, methods, and so forth have a consistent representation in all languages. For example, you can output a line of text to the console the same way across all .NET languages by using the WriteLine( ) method of the Console object, as we have seen elsewhere in this book. This consistent framework requires less development training and enables higher programmer productivity.
Since a full discussion of the entire set of classes in the .NET Framework is beyond the scope of this book (see O'Reilly's In a Nutshell .NET series), we talk about the System.Object class and present the major namespaces in the .NET Framework, opening the doors for you to step into this world.
Every type in .NET is an object, meaning that it must derive directly or indirectly from the Object class. If you don't specify a base class when you define a class, the compiler will inject this requirement into the IL code. The Object class supports a commonality that all .NET classes inherit and thus automatically provide to their consumers. The Object class exposes the public methods listed in Table 3-1, which you can invoke on any given .NET object at runtime.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Common Programming Model
Without the .NET Framework, programmers must choose from amongst a wealth of APIs or libraries that support system services. For example, if you want to write GUI applications on Windows, you have a slew of options from which to choose, including the Win32 API, MFC, ATL, VB, and so on. Once you've chosen the library, you have to learn how to use the structures, classes, functions, interfaces, and so forth that the library provides. Unfortunately, this knowledge doesn't transfer directly into a different environment. For instance, there's a big difference between the code to manage IO in MFC and the code to manage IO in VB.
One of the goals of the .NET Framework is to bring commonality to application development by providing a framework of common classes to developers who are using compilers that generate IL. This common framework is extremely helpful: if you know how to take advantage of IO functionality in .NET using your favorite language, you can easily port that code to another language. This is possible because the namespaces, classes, methods, and so forth have a consistent representation in all languages. For example, you can output a line of text to the console the same way across all .NET languages by using the WriteLine( ) method of the Console object, as we have seen elsewhere in this book. This consistent framework requires less development training and enables higher programmer productivity.
Since a full discussion of the entire set of classes in the .NET Framework is beyond the scope of this book (see O'Reilly's In a Nutshell .NET series), we talk about the System.Object class and present the major namespaces in the .NET Framework, opening the doors for you to step into this world.
Every type in .NET is an object, meaning that it must derive directly or indirectly from the Object class. If you don't specify a base class when you define a class, the compiler will inject this requirement into the IL code. The Object class supports a commonality that all .NET classes inherit and thus automatically provide to their consumers. The Object class exposes the public methods listed in Table 3-1, which you can invoke on any given .NET object at runtime.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Core Features and Languages
Since one of .NET's goals is to support a common paradigm for application programming, it must specify and utilize programming concepts consistently. In this section, we will examine three core Microsoft .NET languages, including Managed C++, VB.NET, and C#, and several core programming concepts that all .NET languages support, including:
Namespace
Mitigates name collisions.
Interface
Specifies the methods and properties that must be implemented by objects that expose the interface.
Encapsulation
In object-oriented languages, allows a class to encapsulate all its data and behavior.
Inheritance
Allows a class to inherit from a parent class so that it can reuse rich functionality that the parent class has implemented, thus reducing development effort and programming errors.
Polymorphism
Permits developers to specify or implement behaviors in a base class that can be overridden by a derived class. This is a very powerful feature because it allows developers to select the correct behavior based on the referenced runtime object.
Exception handling
Allows us to write easier-to-understand code because it allows us to capture all errors in a common, understandable pattern—totally opposite to that of nine levels of nested conditional blocks.
While this is not a complete list of concepts that .NET supports, it includes all the major .NET concepts that we want to cover in this section. We will show you examples of all these features in Managed C++, VB.NET, and C#. These concepts are nothing new: we're merely demonstrating how they're represented in all .NET languages.
Before we start, you should understand first what our examples will accomplish. First, we will create a namespace, called Lang, that encapsulates an interface, ISteering. Then we will create two classes: Vehicle, which is an abstract base class that implements ISteering, and Car, which is a derivative of Vehicle. We will support an entry point that instantiates and uses Car within a try block. We will unveil other details as we work through the examples.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Language Integration
In the previous section, we saw that you can take advantage of .NET object-oriented concepts in any .NET language. In this section, we show that you can take advantage of language integration -- the ability to derive a class from a base that is specified in a totally different language, or to catch exceptions thrown by code written in a different language, or to take advantage of polymorphism across different languages, and so forth.
Before we discuss the examples in this section, let's first understand what we want to accomplish (see Figure 3-1). We will first use Managed C++ to develop a Vehicle class that is an abstract base class. The Vehicle class exposes three polymorphic methods, including TurnLeft( ), TurnRight( ), and ApplyBrakes( ). We will then use VB.NET to develop a Car class that derives from Vehicle and overrides these three virtual methods. In addition, we will use C# to develop the Plane class that derives from Vehicle and overrides these three virtual methods.
Figure 3-1: Polymorphism across languages
In the upcoming code example, we can tell a Vehicle to TurnLeft( ) or TurnRight( ), but what turns left or right depends upon the target object, whether a Car or a Plane. Unlike the examples in the last section, the examples here illustrate that we can inherit classes and call virtual functions from ones that are defined in another language. In addition, we will demonstrate in our test program that exception handling works across different languages.
Let's use Managed C++ to develop the Vehicle class, which is an abstract base class because ApplyBrakes( ) is a pure virtual function. Vehicle implements the ISteering interface to support turning left and turning right. Since the ApplyBrakes( ) function is a pure virtual function, any concrete derivative of Vehicle must implement this method:
#using <mscorlib.dll>
using namespace System;

public _  _gc _  _interface ISteering
{
  void TurnLeft(  );
  void TurnRight(  );
};

public _  _gc class Vehicle : public ISteering  
{
  public:

    virtual void TurnLeft(  )
    {
      Console::WriteLine("Vehicle turns left."); 
    }

    virtual void TurnRight(  )
    {
      Console::WriteLine("Vehicle turn right."); 
    }

    virtual void ApplyBrakes(  ) = 0; 
};
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
We started this chapter by telling you that .NET provides a common programming model, which reduces the learning curve and increases productivity. Once you've learned how to do something using the classes in the .NET Framework, this knowledge will transfer to any .NET language. We then illustrated that we could write the same type of code, supporting major .NET features, in any given language. Finally, we proved to you that .NET indeed supports language integration, which was never possible using Microsoft platforms and tools, prior to .NET.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Working with .NET Components
Having seen the language-integration examples in the previous chapter, you now know that all .NET assemblies are essentially binary components. You can treat each .NET assembly as a component that you can plug into another component or application, without the need for source code, since all the metadata for the component is stored inside the .NET assembly. While you have to perform a ton of plumbing to build a component in COM, creating a component in .NET involves no extra work, as all .NET assemblies are components by nature.
In this chapter, we examine the more advanced topics, including component deployment, distributed components, and enterprise services, such as transaction management, object pooling, role-based security, and message queuing.
For a simple program like hello.exe that we built in Chapter 2, deployment is easy: copy the assembly into a directory, and it's ready to run. When you want to uninstall it, remove the file from the directory. However, when you want to share components with other applications, you've got to do some work.
In COM, you must store activation and marshaling information in the registry for components to interoperate; as a result, any COM developer can discuss at length the pain and suffering inherent in COM and the system registry. In .NET, the system registry is no longer necessary for component integration.
In the .NET environment, components can be private, meaning that they are unpublished and used by known clients, or shared, meaning that they are published and used by all clients. This section discusses several options for deploying private and shared components.
If you have private components that are used only by specific clients, you have two deployment options. You can store the private components and the clients that use these components in the same directory, or you can store the components in a specific directory that the client can access. Since these clients use the exact private components that they referenced at build time, the CLR doesn't support version checking or enforce version policies on private components.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Deployment Options
For a simple program like hello.exe that we built in Chapter 2, deployment is easy: copy the assembly into a directory, and it's ready to run. When you want to uninstall it, remove the file from the directory. However, when you want to share components with other applications, you've got to do some work.
In COM, you must store activation and marshaling information in the registry for components to interoperate; as a result, any COM developer can discuss at length the pain and suffering inherent in COM and the system registry. In .NET, the system registry is no longer necessary for component integration.
In the .NET environment, components can be private, meaning that they are unpublished and used by known clients, or shared, meaning that they are published and used by all clients. This section discusses several options for deploying private and shared components.
If you have private components that are used only by specific clients, you have two deployment options. You can store the private components and the clients that use these components in the same directory, or you can store the components in a specific directory that the client can access. Since these clients use the exact private components that they referenced at build time, the CLR doesn't support version checking or enforce version policies on private components.
To install your applications in either of these cases, perform a simple xcopy of your application files from the source installation directory to the destination directory. When you want to remove the application, remove these directories. You don't have to write code to store information into the registry, so there's no worrying about whether you've missed inserting a registry setting for correct application execution. In addition, because nothing is stored in the registry, you don't have to worry about registry residues.

Section 4.1.1.1: One-directory deployment

To specify component location in the same directory as the client application, use the following syntax (as we did in a Chapter 3 example):
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Distributed Components
A component technology should support distributed computing, allowing you to activate and invoke remote services, as well as services in another application domain. Distributed COM, or DCOM, is the wire protocol that provides support for distributed computing using COM. While DCOM is fine for distributed computing, it is inappropriate for global cyberspace because it doesn't work well in the face of firewalls and NAT software. Some other shortcomings of DCOM are expensive lifecycle management, protocol negotiation, and binary formats.
To eliminate or at least mitigate these shortcomings, .NET provides a host of different distributed support. The Remoting API in .NET allows you to use a host of channels, such as TCP and HTTP (which uses SOAP), for distributed computing. It even permits you to plug in your own custom channels, should you require this functionality. Best of all, since the framework is totally object-oriented, distributed computing in .NET couldn't be easier. To show you how simple it is to write a distributed application in .NET, let's look at an example using sockets, otherwise known as the TCP channel in .NET.
In this example, we'll write a distributed Hello application, which outputs a line of text to the console whenever a client invokes its exposed method, SayHello( ). Since we're using the TCP channel, we'll tell the compiler that we need the definitions in the System.Runtime.Remoting and System.Runtime.Remoting.Channels.Tcp namespaces.
Note that this class, CoHello, derives from MarshalByRefObject.
This is the key to distributed computing in .NET because it gives this object a distributed identity, allowing the object to be referenced across application domains, or even process and machine boundaries. A marshal-by-reference object requires a proxy to be set up on the client side and a stub to be set up on the server side, but since both of these are automatically provided by the infrastructure, you don't have to do any extra work. Your job is to derive from MarshalByRefObject to get all the support for distributed computing.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
COM+ Services in .NET
COM programming requires lots of housekeeping and infrastructure-level code to build large-scale, enterprise applications. Making it easier to develop and deploy transactional and scalable COM applications, Microsoft released Microsoft Transaction Server (MTS). MTS allows you to share resources, thereby increasing the scalability of an application. COM+ Services were the natural evolution of MTS. While MTS was just another library on top of COM, COM+ Services were subsumed into the COM library, thus combining both COM and MTS into a single runtime.
COM+ Services have been very valuable to the development shops using the COM model to build applications that take advantage of transactions, object pooling, role-based security, etc. If you develop enterprise .NET applications, the COM+ Services in .NET are a must.
In the following examples, rather than feeding you more principles, we'll show you examples for using major COM+ Services in .NET, including examples on transactional programming, object pooling, and role-based security. But before you see these examples, let's talk about the key element—attributes—that enable the use of these services in .NET.
Attributes are the key elements that help you write less code and allow an infrastructure to automatically inject the necessary code for you at runtime. If you've used IDL (Interface Definition Language) before, you have seen the in or out attributes, as in the following example:
HRESULT SetAge([in] short age);
HRESULT GetAge([out] short *age);
IDL allows you to add these attributes so that the marshaler will know how to optimize the use of the network. Here, the in attribute tells the marshaler to send the contents from the client to the server, and the out attribute tells the marshaler to send the contents from the server to the client. In the SetAge( ) method, passing age from the server to the client will just waste bandwidth. Similarly, there's no need to pass age from the client to the server in the GetAge( ) method.

Section 4.3.1.1: Developing custom attributes

Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Message Queuing
In addition to providing support for COM+ Services, .NET also supports message queuing. If you've used Microsoft Message Queuing (MSMQ) services before, you'll note that the basic programming model is the same but the classes in the System.Messaging namespace make it extremely easy to develop message-queuing applications. The System.Messaging namespace provides support for basic functionality, such as connecting to a queue, opening a queue, sending messages to a queue, receiving messages from a queue, and peeking for messages on the queue. To demonstrate how easy it is to use the classes in System.Messaging, let's build two simple applications: one to enqueue messages onto a private queue on the local computer and another to dequeue these messages from the same queue.
Here's a simple program that enqueues a Customer object onto a private queue on the local computer. Notice first that we need to include the System.Messaging namespace because it contains the classes that we want to use:
using System;
using System.Messaging;
            
While the following Customer structure is very simple, it can be as complex as you want because it will be serialized into an XML-formatted buffer by default before it's placed into the queue.
public struct Customer
{
  public string Last;
  public string First;
}
Our program first checks whether a private queue on the local computer exists. If this queue is missing, the program will create it. Next, we instantiate a MessageQueue class, passing in the target queue name. Once we have this MessageQueue object, we invoke its Send( ) method, passing in the Customer object, as shown in the following code. This will put our customer object into our private queue.
public class Enqueue
{
  public static void Main(  ) 
  {
    try 
    {
      string path = ".\\PRIVATE$\\NE_queue";
                     if(!MessageQueue.Exists(path))
      {
        // Create our private queue.
        MessageQueue.Create(path);
      }

      // Initialize the queue.
      MessageQueue q = new MessageQueue(path);
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
In this chapter, we've touched on many aspects of componentization, including deployment strategies, distributed computing, and enterprise services such as transaction management, object pooling, role-based security, and message queuing. We have to give due credit to Microsoft for making componentization easier in the .NET Framework. Case in point: without .NET, it would be impossible for us to illustrate the complete code for all of these programs in a single chapter of a book.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 5: Data and XML
Almost everything we do in the software industry relates to data in some way. At some point, all software developers must deal with data, perhaps using a database, text file, spreadsheet, or some other method of data storage. There are many different methods and technologies for using, manipulating, and managing data, and newer methods are continually introduced to enhance existing ones. These methods range from function-based APIs to object-based frameworks and proprietary libraries.
Several years ago, it was common for a simple VB desktop application to access a private Microsoft Access database stored on the local hard disk, but this is no longer a typical scenario. Today's applications take advantage of distributed-component technologies to exploit scalability and interoperability, thus widening the reach of the application to the enterprise. While ActiveX Data Objects (ADO) served a typical VB application well a few years ago, it might soon fail to meet the increasing demands for better scalability, performance, and interoperability across multiple platforms.
Here's where ADO.NET comes in. ADO.NET provides huge benefits that allow us to build even better enterprise applications. In this chapter, you will learn the benefits of ADO.NET, the ADO.NET architecture, the main classes in ADO.NET and how they work, and the integration of ADO.NET and XML.
Microsoft ADO.NET's object model encompasses two distinct groups of classes: content components and managed-provider components. The content components include the DataSet class and other supporting classes such as DataTable, DataRow, DataColumn, and DataRelation. These classes contain the actual content of a data exchange. The managed-provider components assist in data retrievals and updates. Developers can use the connection, command, and data reader objects to directly manipulate data. In more typical scenarios, developers use the DataAdapter class as the conduit to move data between the data store and the content components. The data can be actual rows from a database or any other form of data, such as an XML file or an Excel spreadsheet.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
ADO.NET Architecture
Microsoft ADO.NET's object model encompasses two distinct groups of classes: content components and managed-provider components. The content components include the DataSet class and other supporting classes such as DataTable, DataRow, DataColumn, and DataRelation. These classes contain the actual content of a data exchange. The managed-provider components assist in data retrievals and updates. Developers can use the connection, command, and data reader objects to directly manipulate data. In more typical scenarios, developers use the DataAdapter class as the conduit to move data between the data store and the content components. The data can be actual rows from a database or any other form of data, such as an XML file or an Excel spreadsheet.
Figure 5-1 shows the high-level architecture of ADO.NET. ADO developers should have no problems understanding connection and command objects. We offer a brief overview then go into more detail in the rest of this chapter.
Figure 5-1: High-level architecture of ADO.NET
A data reader is a new object providing fast, forward-only, and read-only access to data. This structure is similar to an ADO Recordset, which has server-side, forward-only, and read-only cursor types.
The DataSet class is analogous to a lightweight cache of a particular database from the data store. It allows reading and writing of data and schema in XML, and it is tightly integrated with XmlDataDocument, as you will see later.
The DataAdapter class serves as a higher-level abstraction of the connection and command classes. It enables you to load content from a data store into a DataSet and reconcile DataSet changes back to the data store.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
ADO.NET Benefits
ADO.NET brings with it a number of benefits, which fall into the following categories:
Interoperability
The ability to communicate across heterogeneous environments.
Scalability
The ability to serve a growing number of clients without degrading system performance.
Productivity
The ability to quickly develop robust data access applications using ADO.NET's rich and extensible component object model.
Performance
An improvement over previous ADO versions due to the disconnected data model.
All communication involves data exchange, whether the communication between distributed components is through a request/response methodology or a message-based facility. Current distributed systems assume that the components involved in the communication are using the same protocol and data format. This assumption is too restrictive for a client base to expand across an enterprise or for multiple companies. Data-access layers should impose no such restrictions.
In current Microsoft Windows Distributed interNet Applications (DNA) Architecture, application components pass data back and forth as ADO disconnected recordsets. The data-providing components, as well as the data-consuming components, are required to use the Component Object Model (COM). The payload, the actual content we are passing around, is packaged in a data format called Network Data Representation (NDR). These NDR packages are streamed between components.
There are two issues with current Windows DNA systems. The first is the requirement that both ends of the communication pipe have the COM library. The second issue is that it is difficult to set up and manage these communications across firewalls. If your middle-tier components are COM/DCOM-based and you are using them within your intranet, you are in good shape. To put it another way: if all your components use Microsoft technology, you're fine. With the advent of electronic commerce (e-commerce), however, enterprise applications must interoperate with more than just Microsoft-development shops. ADO must improve for cross-platform components to seamlessly share data, breaking away from the limitations of COM/DCOM.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Content Components
Content preview·