Microsoft .NET Framework

The .NET Framework is the next iteration of Microsoft's platform for developing component-based software. It provides fundamental advances in runtime services for application software. It also supports development of applications that can be free of dependencies on hardware, operating 
system, and language compiler.

This chapter provides an overview of the architecture of the .NET Framework and describes the base features found in the core of its class library.
Common Language Infrastructure (CLI) and Common Language Runtime (CLR)

At the heart of the .NET Framework is a new mechanism for loading and running programs and managing their interactions. This mechanism is described in the Common Language Infrastructure (CLI), a specification for a runtime environment that allows software components to:
  • Pass data between each other without regard to the programming language in which each component is written
  • Execute on different operating systems and on different hardware platforms without having to recompile the high-level source code
Although the CLI specification was created by Microsoft, it has since been submitted to the ECMA standards organization (http://www.ecma.ch), which now has responsibility and control over it.

The CLI is just a specification—it has to be implemented in order to be useful. An implementation of the CLI is known as a Common Language Runtime (CLR). Microsoft's CLR implementation on the Windows platform is not under ECMA's control, but it is Microsoft's intention that the CLR be a fully compliant implementation of the CLI. As of this writing, the CLI has not been implemented on non-Windows platforms, but Microsoft and others have announced intentions to do so.

The CLI specifies how executable code is loaded, run, and managed. The portion of the CLR that performs the tasks of loading, running, and managing .NET applications is called the virtual execution system (VES). Code run by the VES is called managed code .
The CLI greatly expands upon concepts that exist in Microsoft's Component Object Model (COM). As its core feature, COM specifies how object interfaces are laid out in memory. Any component that can create and consume this layout can share data with other components that do the same. COM was a big step forward when it was introduced (circa 1992), but it has its shortcomings. For example, in spite of its name, COM actually has no concept of an object—only object interfaces. Therefore, COM can't support passing native types from one component to another.
Common Type System (CTS)
The CLI specification defines a rich type system that far surpasses COM's capabilities. It's called the Common Type System (CTS). The CTS defines at the runtime level how types are declared and used. Previously, language compilers controlled the creation and usage of types, including their layout in memory. This led to problems when a component written in one language tried to pass data to a component written in a different language. Anyone who has written Visual Basic 6 code to call Windows API functions, for instance, or who has tried to pass a JavaScript array to a component written either in Visual Basic 6 or C++, is aware of this problem. It was up to the developer to translate the data to be understandable to the receiving component. The CTS obliterates this problem by providing the following features:
  • Primitive types (Integer, String, etc.) are defined at the runtime level. Components can easily pass instances of primitive types between each other because they all agree on how that data is formatted.
  • Complex types (structures, classes, enumerations, etc.) are constructed in a way that is defined at the runtime level. Components can easily pass instances of complex types between each other because they all agree on how complex types are constructed from primitive types.
  • All types carry rich type information with them, meaning that a component that is handed an object can find out the definition of the type of which the object is an instance. This is analogous to type libraries in COM, but the CTS is different because the type information is much richer and is guaranteed to be present.

Namespaces

They are mentioned again here because they aren't just a Visual Basic .NET concept; they are also used by the CLR and by other languages that target the .NET platform. It's important to keep in mind that to the CLR, a namespace is just part of a fully qualified type name, and nothing more. See Section 3.4.2 later in this chapter for more information.


Portions of the CLI

The CLI specification recognizes that the CLR can't be implemented to the same extent on all platforms. For example, the version of the CLR implemented on a cell phone won't be as versatile as the one implemented on Windows 2000 or Windows XP. To address this issue, the CLI defines a set of libraries. Each library contains a set of classes that implement a certain portion of the CLI's functionality. Further, the CLI defines profiles. A profile is a set of libraries that must be implemented on a given platform.
The libraries defined by the CLI are:


Runtime Infrastructure Library

This library provides the core services that are needed to compile and run an application that targets the CLI.


Base Class Library

This library provides the runtime services that are needed by most modern programming languages. Among other things, the primitive data types are defined in this library.


Network Library

This library provides simple networking services. 

Reflection Library 
This library provides the ability to examine type information at runtime and to invoke members of types by supplying the member name at runtime, rather than at compile time.


XML Library

This library provides a simple XML parser. 

Floating Point Library 
This library provides support for floating point types and operations.

Programming Visual Basic .NET


Extended Array Library

This library provides support for multidimensional arrays. The profiles defined by the CLI at this time are:


Kernel Profile

This profile defines the minimal functionality of any system claimed as an implementation of the CLI. CLRs that conform to the Kernel Profile must implement the Base Class Library and the Runtime Infrastructure Library.


Compact Profile

This profile includes the functionality of the Kernel Profile, plus the Network Library, the Reflection Library, and the XML Library. It is intended that an implementation of the Compact Profile can be lightweight, yet provide enough functionality to be useful.

Additional profiles will be defined in future versions of the CLI specification. Any given implementation of the CLI is free to implement more than the functionality specified by these minimal profiles. For example, a given implementation could support the Compact Profile but also support the Floating Point Library. The .NET Framework on Windows 2000 supports all the CLI libraries, plus additional libraries not defined by the CLI.

Note that the CLI does not include such major class libraries as Windows Forms, ASP.NET, and ADO.NET. These are Microsoft-specific class libraries for developing applications on Windows platforms. Applications that depend on these libraries will not be portable to other implementations of the CLI unless Microsoft makes those class libraries available on those other implementations.


Modules and Assemblies

A module is an .exe or .dll file. An assembly is a set of one or more modules that together make up an application. If the application is fully contained in an .exe file, fine—that's a one-module assembly. If the .exe is always deployed with two .dll files and one thinks of all three files as comprising an inseparable unit, then the three modules together form an assembly, but none of them does so by itself. If the product is a class library that exists in a .dll file, then that single .dll file is an assembly. To put it in Microsoft's terms, the assembly is the unit of deployment in .NET.

An assembly is more than just an abstract way to think about sets of modules. When an assembly is deployed, one (and only one) of the modules in the assembly must contain the assembly manifest, which contains information about the assembly as a whole, including the list of modules contained in the assembly, the version of the assembly, its culture, etc. The command-line compiler and the Visual Studio .NET compiler create single-module assemblies by default. Multiple-module assemblies are not used in this book.

Assembly boundaries affect type resolution. When a source file is compiled, the compiler must resolve type names used in the file to the types' definitions. For types that are defined in the same source project, the compiler gets the definitions from the code it is compiling. For types that are defined elsewhere, the compiler must be told where to find the definitions. This is done by referencing the assemblies that contain the compiled type definitions. When the command-line compiler is used, the /reference switch identifies assemblies containing types used in the project being compiled. An assembly has the same name as the module that contains the assembly manifest, except for the file extension. In some cases, however, an assembly is specified by giving the full name of the module that contains the assembly manifest. For example, to compile an application that uses the System.Drawing.Point class, you could use the following command line:
CODES:
The documentation for the command-line compiler states that the argument to the reference switch is an assembly. This is not quite accurate. The argument is the name of the module that contains the assembly manifest for an assembly.

If more than one assembly needs to be referenced, you can list them all in the same /reference switch, separated by commas, like this:
CODES:
The Visual Basic .NET command-line compiler automatically references two assemblies: mscorlib.dll, which contains most of the types found in the System namespace; and Microsoft.VisualBasic.dll, which contains the types found in the Microsoft.VisualBasic namespace.

When you're working within the Visual Studio .NET IDE, external assemblies are referenced by doing the following:
  1. In the Solution Explorer window, right-click on References, then click on Add Reference. The Add Reference dialog box appears, as shown in Figure 1.
  2. Scroll down to find the desired assembly.
  3. Double-click or highlight the assembly name, and press the Select button. The assembly name appears in the Selected Components frame of the dialog box.
  4. Select additional assemblies, or click OK.
Figure 1

Global Assembly Cache (GAC)

By default, assemblies are not shared. When one assembly is dependent on another, the two assemblies are typically deployed into a single application directory. This makes it easy to install and remove an application. To install an application, simply create the application directory and copy the files into it. To delete the application, just delete the application directory. The Windows Registry is not used at all.

If an assembly must be shared among more than one program, either it can be copied into each appropriate application directory or it can be installed into the global assembly cache (GAC). The GAC is an area on disk (typically, it's the assembly subdirectory of the Windows directory) that holds assemblies to be shared among all applications. All of the .NET Framework assemblies reside in the GAC. (See Figure 2 for a partial view of the assemblies in a typical GAC.) Placing an assembly into the GAC should be avoided if possible: it makes application installation and removal more difficult. This is because the Windows Installer or gacutil.exe must be used to manipulate the GAC—you can no longer simply copy or remove the application directory. Installing assemblies into the GAC is not covered in this book. For information, point your browser to http://msdn.microsoft.com and perform a search for "Deploying Shared Components."

Figure 2
Comparison of Assemblies, Modules, and Namespaces
It's easy to confuse the three concepts of namespace, module, and assembly. Here is a recap:
Namespace
A portion of a type name. Specifically, it is the portion that precedes the final period in a fully qualified type name.
Module
A file that contains executable code (.exe or .dll).
Assembly
A set of one or more modules that are deployed as a unit. The assembly name is the same as the name of the module that contains the assembly manifest, minus the filename extension.
Depending on how things are named, it can seem like these three terms are interchangeable. For example, System.Drawing.dll is the name of a module that is deployed as part of the .NET Framework. As it happens, this module is part of a single-module assembly. Because assemblies are named after the module that contains the assembly manifest, the assembly is called System.Drawing. A compiler will reference this assembly as System.Drawing.dll. Many (but not all) of the types in this assembly have a namespace of System.Drawing. (Other types in the System.Drawing assembly have namespaces of System.Drawing.Design, System.Drawing.Drawing2D, System.Drawing.Imaging, System.Drawing.Printing, and System.Drawing.Text.) Note that even though the namespace, module, and assembly are similarly named in this case, they are distinct concepts. Note in particular that importing a namespace and referencing an assembly are different operations with different purposes. The statement:
CODES:
allows the developer to avoid typing the fully qualified names of the types in the System.Drawing namespace. It does not reference the assembly in which those types are defined. To use the types, the System.Drawing assembly (contained in the System.Drawing.dll module) must be referenced as described earlier in this section. 

In other cases, namespace and assembly names don't correspond. One example is the System namespace. Some types with this namespace are found in the mscorlib assembly, and others are found in the System assembly. In addition, each of those assemblies has types with other namespaces. For example, the System assembly contains types with the Microsoft.VisualBasic namespace, even though most of the types with that namespace are found in the Microsoft.VisualBasic assembly. (The reason for this apparent inconsistency is actually quite sound. Namespaces group types according to functionality, while assemblies tend to group types according to which types are most likely to be used together. This improves performance because it minimizes the number of assemblies that have to be loaded at runtime.)

When thinking about namespaces, just remember that types can have any namespace at all, regardless of where they're defined—the namespace is just part of the type name.

Continue from Application Domains

No comments:

Post a Comment