After completing this chapter, you will be able to:
Identify the components of the Microsoft .NET Framework.
Work with the major components of the .NET Framework.
Recognize the main namespaces that make up the .NET Framework class library.
In previous chapters, you learned how to use C++/CLI to build simple applications. Now, it’s time to move on to learn how to build real Microsoft .NET applications that involve GUIs, databases, web servers, and all the other mechanisms needed by the modern Microsoft Windows application. And that’s where the .NET Framework comes in.
The .NET Framework is the library of classes that you use to build Windows applications. It is large, complex, and far-reaching in its scope. This chapter gives you an overview of what the .NET Framework is and what it can do before we cover some of its features in more detail in later chapters.
The .NET Framework is a computing platform that has been designed by Microsoft to simplify the development of modern applications, such as the following:
Applications that use sophisticated GUI front ends
Applications that use the Internet
Applications that are distributed over more than one computer
Applications that make use of databases and other data sources
There are two main components to the .NET Framework: the Common Language Runtime and the .NET Framework class library. You’ll examine both components in this chapter.
You’ve already met the Common Language Runtime (CLR) because this is the part of .NET that manages your code as it runs, providing services such as garbage collection. The CLR is a run-time execution engine that is responsible for executing code within the .NET environment, providing services such as security, memory management, and remoting (communication between objects in different domains, processes, or computers). Code that is run by the CLR is known as managed code; code that executes outside the control of the CLR is unmanaged code. All Microsoft Visual Basic and C# code is managed, but it’s possible to write both managed and unmanaged code in Microsoft Visual C++ and to have both types of code working together in the same application.
All .NET languages compile down into an intermediate form called Microsoft Intermediate Language (MSIL, or just IL.)
IL is similar to Java bytecode in that it’s an intermediate form of code produced by the compiler that can’t be directly executed on a target system. IL code is also portable and is always converted into native code before it’s executed, which is done by a Just-In-Time (JIT) compiler. This conversion might happen on demand, function-by-function as an application executes, or all at once when an application is installed.
One of the great innovations of IL is that it isn’t simply a low-level, machine-independent object code. In fact, support for object-oriented functionality—such as the ideas of classes, encapsulation and data-hiding, polymorphism, and inheritance—is built into IL, so you can view it as a type of object-oriented assembler language. This functionality makes it far more powerful than Java bytecode, and it makes it possible for you to perform cross-language object-oriented programming, easily calling members in C++/CLI classes from Visual Basic, and vice-versa, and even inheriting from a C++/CLI class in Visual Basic.
If you’re interested in seeing what IL looks like, you can use the IL Disassembler tool, ILDASM, to open a .NET executable and show you the code in IL. There’s an example of how to do so in the section Metadata later in the chapter.
The Common Type System (CTS) provides a specification for how types are defined, managed, and used, which is an important part of the .NET cross-language integration. The CTS provides a set of rules that languages must obey, which helps to ensure that types created in different languages can interoperate with one another.
The Common Language Specification (CLS) is a set of rules and constraints that compiler and library writers need to follow to ensure that the languages and code they produce will interoperate with other .NET languages. The CLS forms a subset of the CTS, and if a language or a library is CLS-compliant, it will completely interoperate with other CLS-compliant languages.
You’ll see in the online documentation that some .NET member functions are marked as not CLS-compliant, which means that they might not be accessible from some .NET languages. For example, functions that use unsigned integers are not CLS-compliant because unsigned integers aren’t supported by Visual Basic. As a result, unsigned integers are not included in the types specified by the CLS.
The .NET Framework class library is an object-oriented library of classes that provides all the tools you need to write a wide variety of applications.
Since Windows was first released, programmers have written Windows applications using the Windows API (application programming interface). This API gives you a large number of C functions—several thousand, in fact—that you can call from your applications to interact with Windows. However, there are two main problems with the Windows API: first, it isn’t object-oriented, and second, it’s a C library, so it can’t easily be used from every language.
One of the benefits of object-oriented programming is the help that it gives in structuring and managing large-scale projects. The Windows API has grown to several thousand functions, and it becomes harder and harder to manage such a large collection of unstructured routines. In addition to its other benefits (such as encapsulation and polymorphism), object-oriented programming lets you impose a structure on code. So, for example, a Dialog class can contain all the functions relating to dialog boxes. This ability makes it much easier to use a library the size of the Windows API.
The second problem with the Windows API is that it’s basically written for C programmers, so it uses many features that are unique to C, such as pointers and null-terminated strings, which makes it hard—and sometimes impossible—to use some functionality from languages other than C or C++. You also tend to need a lot of ugly “plumbing” to interface between languages such as Visual Basic and the API.
The .NET Framework class library provides a set of classes that can be used from any .NET language because it works at the IL level. All .NET languages compile down to the same intermediate code, and because they all use references and agree on the basic set of value types, they can all use the classes defined in the class library. This is a huge advantage and provides language interoperability on a scale never seen before.
Assemblies are the basic building blocks with which .NET applications are constructed, and they’re the fundamental unit of deployment and versioning. Assemblies contain IL code, metadata that describes the assembly and its contents, and any other files needed for run-time operation. An assembly is therefore much more self-contained than a standard Windows executable or Component Object Model (COM) object because there is no reliance on external sources of information such as the Windows Registry. Every .NET type is part of an assembly, and no .NET type can exist outside an assembly.
There are several aspects by which assemblies are fundamental to the .NET world:
Versioning The assembly is the smallest unit to which versioning is applied, and the assembly manifest describes the assembly’s version together with the versions of any assemblies on which it depends. This information means that it’s possible to check that components with the wrong version information aren’t being used at run time.
Deployment Assemblies are loaded only as needed, which makes them highly suitable for distributed applications.
Type A type’s identity includes the assembly in which it resides. Two types with the same name living in two different assemblies are considered to be two completely different types.
Security The boundary between assemblies is where security permissions are checked.
.NET classes are self-describing, which means that they carry descriptive information with them in the .exe or .dll file. This information, called metadata, includes the following:
The name, version, and culture-specific information (such as the language and calendar used) for the assembly
The types that are exported by the assembly
Other assemblies on which this one depends
Security permissions needed to run
Information for each type in the assembly: name, visibility, base class, interfaces implemented, and details of members
Additional attribute information
Most of the metadata is standard and is created by the compiler when it produces the IL code, but you can use attributes to add extra metadata information.
The following exercise shows you how to modify the standard metadata produced by the compiler.
Start Microsoft Visual Studio 2012 and create a new CLR Console Application project named Meta1.
Open Solution Explorer and look at the Source Files folder.
You can see that the project contains three C++ source files: Meta1.cpp is the code for the application, AssemblyInfo.cpp contains definitions of the standard metadata items that you can modify, and StdAfx.cpp is there to include the StdAfx.h header file.
Open AssemblyInfo.cpp.
The file contains a number of lines that look like the following:
[assembly:AssemblyTitleAttribute("Meta1")]; [assembly:AssemblyDescriptionAttribute("")]; [assembly:AssemblyConfigurationAttribute("")]; [assembly:AssemblyCompanyAttribute("")]; [assembly:AssemblyProductAttribute("Meta1")]; [assembly:AssemblyCopyrightAttribute("Copyright (c) 2012")]; [assembly:AssemblyTrademarkAttribute("")]; [assembly:AssemblyCultureAttribute("")];
Metadata is added to C++ code by enclosing declarations in square brackets ([]). Metadata is most often attached to code to describe classes and functions. Here, the keyword assembly: at the start of the attribute means that this attribute applies to an assembly, as opposed to being attached to code. There’s a set of standard attributes that you can use to change the metadata compiled into an assembly, and most of them are listed in AssemblyInfo.cpp.
Edit the AssemblyCompanyAttribute line to contain some suitable name, such as the following:
[assembly:AssemblyCompanyAttribute("City Power & Light")];
Build the project, which automatically creates the assembly for you. How can you be sure that the metadata in the assembly reflects your change? One way to find out is to use ILDASM, which is part of the .NET SDK. On my system, this is located in the folder Program Files (x86)Microsoft SDKsWindowsv8.0AinNETFX 4.0 Tools.
When the ILDASM window opens, use the File menu to navigate to the Meta1.exe executable and open it. You should see something like the screen shot that follows.
Double-click MANIFEST, which opens a separate window displaying the assembly metadata.
At the top of this listing are the details of the assemblies on which this executable depends. Scroll down until you find the AssemblyCompanyAttribute line, which should read something like the following:
.custom /*0C000005:0A000009*/ instance void ['mscorlib'/* 23000001 */] 'System.Reflection'.'AssemblyCompanyAttribute' /* 0100000D */::.ctor(string) /* 0A000009 */ = ( 01 00 16 41 63 6D 65 20 52 6F 63 6B 65 74 20 53 // ...City Power & 6C 65 64 2C 20 49 6E 63 2E 00 00 ) // Light...
Although the contents are presented in hexadecimal, you can see that the metadata does reflect the change you made to the project.
The .NET Framework class library is made up of a set of classes, interfaces, structures, and enumerations that are contained in over 400 namespaces. This section begins by explaining how to use namespaces in C++/CLI code and then goes on to list some of the major .NET namespaces, together with brief details of their function and content.
You’ve already encountered .NET namespaces in use in C++/CLI code when you’ve used the C++ using keyword, as in the following example:
using namespace System::Collections;
As with traditional C++ namespaces, .NET namespaces provide an additional level of scoping that helps you to organize code and guard against name clashes. Two classes with the same name can be used in an application, provided that they belong to different namespaces. A type name that includes the namespace information is called the fully qualified name, as illustrated in the following examples:
System::Collections::Generic::List // the List<T> class from // System::Collections::Generic System::Threading::Thread // the Thread class from System::Threading
Namespace names in .NET typically consist of more than one word. In C++/CLI, the components of the name are separated by the scope resolution operator (::). In many other .NET languages such as C# and Visual Basic, the components are separated by using a period (.), so in C#, the preceding examples would be as follows:
System.Collections.Generic.List System.Threading.Thread
All classes, interfaces, structures, and enumerations that are part of the .NET Framework class library belong to a namespace. Most of the namespaces provided by Microsoft begin with one of two prefixes. Those that start with System have been developed as part of the .NET Framework class library, whereas those beginning with Microsoft have been developed by other product groups within Microsoft.
Namespace names can have any number of components, but there’s no hierarchical relationship implied in names that contain the same root components. The hierarchical nature of namespace names simply gives you a way to organize your classes. So, for example, System::Collections::Generic and System::Collections both contain collections, yet they aren’t necessarily related in any other way.
If you are a Java programmer, keep in mind that although .NET namespaces look very much like Java package names, there’s no relationship between namespace names and directory paths as there is in Java.
There’s no requirement that all the classes belonging to one namespace are defined in the same .dll file or that a single .dll file contains classes from only one namespace.
C++/CLI applications employ the #using preprocessor directive to import metadata into applications. Remember that metadata is information that describes the types in an assembly, and it includes the fully qualified names of all the types. For example, if the compiler sees a line such as
#using <mscorlib.dll>
it loads the .dll file and reads the metadata for all the types that are defined there. Because mscorlib.dll contains most of the core .NET Framework classes, it imports the metadata for a very large number of types.
The #using keyword means that you have to know which .dll file holds the class or classes that you want to use. Your typical source for this information is the online help.
Some of the fully qualified names can get rather long. Thus, it’s common to use a traditional using directive to specify namespace names so that you can use unqualified names, as shown here:
// Read the metadata for MSCORLIB #using <mscorlib.dll> // Import all the names using namespace System::Collections::Generic; // Now you can use List without having to qualify it List<int> ^pal = gcnew List<int>();
The System namespace, defined in mscorlib.dll, contains a lot of fundamental classes, including the following:
Base classes for commonly used value and reference types, plus the base class for arrays
Events and event handlers
Delegates and interfaces
Attributes
Exceptions
Math
Application environment management
Garbage collection
Local and remote application invocation
Data type conversion
You’ve already seen a lot of types from System in earlier chapters, and some of the other classes are rather obscure, so I won’t go through them in detail. There are a few points that are worth mentioning about some of the classes in System; these are covered in the following sections.
System implements all the basic types defined by the CTS, and you can find these listed in the following table (which also appears in Chapter 9).
Value type | Description | C++/CLI equivalent type |
An 8-bit unsigned integer | ||
An 8-bit signed integer | char | |
A 16-bit signed integer | short | |
A 32-bit signed integer | int or long | |
A 64-bit signed integer | __int64 or long long | |
A 16-bit unsigned integer | unsigned short | |
A 32-bit unsigned integer | unsigned int or unsigned long | |
A 64-bit unsigned integer | unsigned __int64 or unsigned long long | |
A single-precision, 32-bit, floating-point number | float | |
A double-precision, 64-bit, floating-point number | double | |
A Boolean value | bool | |
Char | A 16-bit Unicode character | wchar_t |
A signed integer whose size depends on the platform | No built-in type | |
An unsigned integer whose size depends on the platform | No built-in type |
Keep in mind that several of the types—namely the unsigned integer types and SByte—aren’t CLS-compliant, so be wary of using them when you’re writing code that’s going to be used from other .NET languages.
All .NET languages map these types to native types, so C++/CLI maps int to System::Int32, but you can also use the underlying types directly, if you want.
The Single and Double types implement IEEE-754 floating-point arithmetic. This means that every operation has a defined result, so you never get a divide-by-zero error when performing floating-point math; instead, you get an answer of infinity. The floating-point classes have values to represent positive and negative infinity and “not a number” (often represented as NaN), as well as methods to test for them, as shown in the following example:
double top = 1.0; double bottom = 0.0; double result = top/bottom; if (result == Double::PositiveInfinity) Console::WriteLine("+infinity"); else if (result == Double::NegativeInfinity) Console::WriteLine("-infinity"); else if (result == Double::NaN) Console::WriteLine("Not a number");
Chapter 12, looks at the Collections namespaces, in particular System::Collections::Generic. System::Collections::Generic is implemented in mscorlib.dll, so to use it, you’ll have to include a #using statement, as demonstrated here:
#using <mscorlib.dll>
The following table lists the main classes that you’ll find in the System::Collections::Generic namespace.
Class | Description |
Dictionary<K,V> | A collection of key/value pairs |
A set of objects | |
A doubly linked list of objects | |
List<T> | A strongly typed list of objects, retrievable by index |
A FIFO collection of objects | |
A collection of key/value pairs sorted on the key | |
A collection of objects maintained in sorted order | |
A LIFO stack |
The System::Collections::Generic namespace also defines a series of interfaces that are used to define the behavior of the collection classes. The collection classes themselves implement one or more of these interfaces, and you can use them as the basis for writing your own collection classes. The main interfaces are listed in the following table.
Interface | Description |
Defines the size, enumerator, and synchronization methods for all collections | |
Defines a method for comparing two objects | |
Implemented by collections that manage key/value pairs, such as Hashtable and ListDictionary | |
Defines the GetEnumerator method, which returns an IEnumerator; implemented by almost all collections | |
Defines the properties and methods of enumerators | |
Implemented by classes that define indexed collections of objects | |
Represents a strongly typed, read-only collection of elements | |
Implemented by classes that manage sets of objects |
The System::Diagnostics namespace provides a number of classes with which you can do the following:
Trace application execution
Interact with the debugger
Use the system event log
Start system processes
Monitor system performance
All the classes in System::Diagnostics are implemented in system.dll.
The System::IO namespace, defined in mscorlib.dll, provides the classes that implement the .NET input/output (I/O) functionality. The main classes in this namespace are described in the following table.
As with all the .NET Framework class library classes, these classes are language-independent. They can be used alongside or in place of the C++ stream classes. Chapter 19, delves deeper into some of the System::IO classes. The System::IO classes are in mscorlib.dll.
The System::Windows prefix identifies 50 namespaces that together provide the functionality of Windows Presentation Foundation (WPF), an advanced user interface (UI) framework for .NET introduced in version 3.0. WPF provides all the tools you need to create modern UIs, including support for forms-based applications, 2D and 3D graphics, typography and printing, run-time animation, and comprehensive support for playing media.
In earlier versions of the .NET Framework, you built UIs by using a technology called Windows Forms, which was heavily influenced by Visual Basic.
One key feature of WPF is its use of XAML, an XML markup language, to define user interfaces. This makes it possible to separate the UI from the code, which allows teams to use design tools such as Microsoft Expression Blend in addition to coding tools such as Microsoft Visual Studio.
Networking support is provided by a number of namespaces in the System::Net family. System::Net itself provides an interface to many of the protocols commonly used today, such as manipulating IP addresses, making DNS lookups, talking to HTTP and FTP servers, managing cookies, and authentication.
System::Net::Sockets provides an implementation of the Berkeley Sockets protocol and provides a .NET wrapper around the Windows WinSock API, whereas System::Net::WebSockets provides a managed implementation of the WebSocket interface.
The System::ServiceModel namespaces (over 30 of them) together implement Windows Communication Foundation (WCF), a technology introduced in .NET 3.0 for creating distributed, service-oriented applications.
With WCF, you can build applications out of components hosted in other processes, and even on other computers. This has long been possible, but the technologies used were very different, depending on where your components were located (same process, different process on the same computer, or different process on another computer) and the communication mechanism you wanted to use (TCP/IP, HTTP, messaging).
WCF provides an integrated framework for creating, deploying, and managing distributed components and their clients. Chapter 19 shows you how to write a web service by using WCF.
XML is heavily used throughout the .NET Framework, and several namespaces provide support for creating and manipulating XML, including the following:
System::Xml Provides the basic classes needed for processing XML
System::Xml::Linq Makes it possible to use Language-Integrated Query (LINQ) to work with XML data
System::Xml::Serialization Gives you the ability to serialize .NET objects to and from XML
System::Xml::XPath Contains the XPath parser and evaluation engine
System::Xml::Xsl Contains the Extensible Stylesheet Language (XSL) processor
Using these classes, it’s possible to perform all the manipulation of XML that you’ll ever need to do. These classes make the .NET Framework one of the most productive environments for XML programming. You can find the XML classes in System.Xml.dll, with the LINQ classes in System.Xml.Linq.dll.
The System::Data namespaces hold the classes that implement ADO.NET, a framework with which you can build components to manage data from a number of data sources. Data from different data sources is provided by data providers, five of which are shipped with the .NET Framework.
System.Data.OleDb Object Linking and Embedding Database (OLE DB)–based technology that makes it possible to use many different kinds of data sources—such as relational database tables, Microsoft Excel spreadsheets, and even text files—as if they were databases.
System.Data.Odbc The ODBC provider gives access to Open Database Connectivity (ODBC) data sources, including Microsoft Access databases.
System.Data.SqlClient This provider is optimized for use with Microsoft SQL Server.
System.Data.OracleClient The provider for Oracle makes it possible to work with Oracle databases from .NET code.
System.Data.EntityClient Entity Framework (EF) is an object-relational mapping framework that can be used from ADO.NET, making it possible to map managed objects to a backing database automatically.
The most important class in the System::Data namespace itself is DataSet, which represents an in-memory cache of data retrieved from a data source. A DataSet consists of one or more DataTable objects, and these in turn consist of a collection of DataColumn and DataRow objects. You can use DataSets to work in disconnected mode. This means retrieve data from a database into a DataSet, disconnect from the database server and work with the data locally, and then update the database from the DataSet later.
Because one of the main reasons for introducing the .NET Framework was to make it easier to build web applications, it’s perhaps no surprise that the .NET Framework contains a number of namespaces related to web programming. These are all related to Microsoft ASP.NET, the latest version of Microsoft Active Server Pages technology that is optimized to work in the .NET environment.
The most significant of the Web namespaces are listed here:
System::Web This provides the basic functionality for browser-to-server communication over HTTP, including the HttpRequest and HttpResponse classes that enable an ASP.NET page to exchange data with the client by using HTTP.
System::Web::Mail This makes it possible for you to prepare and send email attachments by using the Simple Mail Transfer Protocol (SMTP) service that is built in to the Windows operating system.
System::Web::Security This provides classes that implement security in ASP.NET.
System::Web::Services This provides the classes with which you can build web services.
System::Web::UI This contains all the classes with which you can build server-side controls.
The features provided by two of these namespaces merit particular mention. A web service is a programmable entity living on a web server that can be accessed by using standard Internet protocols. What this means in practice is that you can expose a function on a web server that others can call. Communication between client and server uses standard protocols such as HTTP, and data is usually passed to and from the web service in XML format by using Simple Object Access Protocol (SOAP). The use of XML over HTTP makes it possible to access web services easily from clients written in just about any programming language on any platform. It’s also possible to find out what services a web server supports, and it’s very easy in Visual Studio 2012 to write clients that make use of web services.
With the System::Web::UI namespaces, you can build server-side controls. You program these as if they were normal controls, but their code executes on the server. The System::Web::UI::HtmlControls namespace contains classes that represent HTML server controls that map directly to standard HTML elements such as buttons and forms. System::Web::UI::WebControls is more abstract, and you can use it to program server-side controls that might not map directly to HTML.
To | Do this |
Use data structures such as dynamic arrays, lists, and hash tables. | Use the classes in the System::Collections::Generic namespace. |
Create a form-based application. | Use the classes in System::Windows::Forms, and derive a class from System::Windows::Forms::Form. |
Work with XML. | Look at the classes in the System::Xml namespace. |
Trace application execution, interact with the event log, or monitor system performance. | Use the classes in the System::Diagnostics namespace. |
Work with databases by using ADO.NET. |
18.191.62.122