Almost all the capabilities of the .NET Framework are exposed via a vast set of managed types. These types are organized into hierarchical namespaces and packaged into a set of assemblies, which together with the CLR comprise the .NET platform.
Some of the .NET types are used directly by the CLR and are essential for the managed hosting environment. These types reside in an assembly called mscorlib.dll and include C#’s built-in types, as well as the basic collection classes, and types for stream processing, serialization, reflection, threading, and native interoperability.
At a level above this are additional types that “flesh out” the CLR-level functionality, providing features such as XML, networking, and LINQ. These reside in System.dll, System.Xml.dll, and System.Core.dll (new to Framework 3.5) and, together with mscorlib, they provide a rich programming environment upon which the rest of the Framework is built.
The remainder of the .NET Framework consists of applied APIs, most of which cover three areas of functionality:
Table 1-16 shows the history of compatibility between each version of C#, CLR, and the .NET Framework. Interestingly, C# 3.0 targets a new Framework version while using the same CLR version as its predecessor. To be precise, C# 3.0 targets an updated version of CLR 2.0, which is installed as part of Framework 3.5. This update is designed not to break compatibility with existing applications.
Table 1-16. C# version CLR version Framework versions
C# version |
CLR version |
Framework versions |
---|---|---|
1.0 |
1.0 |
1.0 |
1.1 |
1.1 |
1.1 |
2.0 |
2.0 |
2.0 |
|
|
3.0 |
3.0 |
2.0 (updated) |
3.5 |
The most fundamental types live directly in the System
namespace. These include C#’s built-in types, the Exception
base class, the Enum
, and Array
, and Delegate
base classes, Nullable
and Type
. The System
namespace also includes:
The System
namespace also defines standard
interfaces such as IDisposable, IFormattable
, and
IComparable
(the latter provides a standard
protocol for order comparison).
The System.Text
namespace contains the StringBuilder
class (the editable or
mutable cousin of string
), and
the types for working with text encodings, such as UTF-8 (Encoding
and its subtypes).
System.Text.RegularExpressions
contains the
Regex
class and supporting types to perform
advanced pattern-based search and replace operations. The samples in LINQPad (www.linqpad.net) include a section demonstrating
the use of regular expressions.
The .NET Framework offers a variety of classes for managing collections of items.
These include both list-based structures such as List<>
(think variable-length array), and
Stack<>
and LinkedList<>
—as well as dictionary-based structures such as Dictionary<,>
(a hashtable) and SortedDictionary<>
(a red-black tree). The classes
work in conjunction with a set of standard interfaces that unify their common
characteristics, namely, IEnumerable<>,
ICollection<>, IList<>
, and IDictionary<,>
. All collection types are defined in the following
namespaces:
System.Collections // Nongeneric collections System.Collections.Generic // Generic collections System.Collections.Specialized System.Collections.ObjectModel // Bases for custom types
The types for writing local LINQ queries (as covered in this book) reside in the
System.Linq
namespace (in the
System.Core.dll assembly). The Framework also provides APIs for
writing LINQ queries over SQL tables (LINQ to SQL) and in-memory XML
documents:
System.Linq // Basic infrastructure System.Xml.Linq // LINQ to XML System.Data.Linq // LINQ to SQL System.Linq.Expressions // For building expressions
You can find examples on using LINQ to XML and LINQ to XML in LINQPad at www.linqpad.net.
XML is used widely within the .NET Framework and thus is supported extensively. LINQ
to XML includes a lightweight XML document object model that can be constructed and
queried through LINQ. The Framework also provides an older “clunky” W3C-compliant
DOM(XmlDocument
) and classes to support XML
schemas, stylesheets, and XPath. Finally, there’s XmlReader
and XmlWriter
, which are
performant low-level forward-only XML reader/writers. The XML namespaces are:
System.Xml // XmlReader, XmlWriter + old W3C DOM System.Xml.Linq // The LINQ to XML DOM System.Xml.Schema // Support for XSD System.Xml.XPath // XPath query language System.Xml.Xsl // Stylesheet support
The easiest XML DOM to work with is LINQ to XML (this is true even if you don’t use the LINQ operators). The LINQ to XML API makes the W3C-compliant API largely redundant, as well as reducing the need to use XPath and XSL.
The Framework also includes an attribute-driven XML serialization engine in System.Xml.Serialization
.
The Framework provides a stream-based model for low-level input/output. Streams are typically used to read and write
directly to files and network connections, and they can be chained or wrapped in
decorator streams to add compression or encryption functionality. The System.IO
namespace contains the low-level stream types
(starting with the abstract Stream
type), and types
for working with files and directories (File, FileInfo,
Directory, DirectoryInfo, DriveInfo
, and Path
), as well as isolated storage:
System.IO // File support + stream types System.IO.Pipes // Support for Windows pipes System.IO.Compression // Compression streams System.IO.IsolatedStorage // Isolated storage streams
You can directly access low-level network
protocols such as HTTP, FTP, TCP/IP, and SMTP via the types in System.Net:
System.Net System.Net.Mail // For sending mail via SMTP System.Net.Sockets // TCP, UDP, and IP
The WebClient
class is a wrapper that
encapsulates most of the client-side functionality for communicating via HTTP and FTP.
The Socket
class provides raw access to TCP and
UDP.
The Framework provides a number of systems for saving and restoring objects to a binary or text representation. Such systems are required for distributed application technologies, such as Windows Communication Foundation (WCF), Web Services, and Remoting, and also to save and restore objects to a file. In total, there are three serialization engines:
The most modern engine, used implicitly by WCF. This engine is excellent at interoperable messaging and for serializing to XML files (particularly when version tolerance or the need to preserve shared object references is important). It can serialize to either XML or binary.
This engine is powerful, easy to use, and well supported throughout the .NET Framework. Remoting uses binary serialization—including when communicating between two application domains in the same process. The disadvantage of this engine is that it tightly couples a type’s internal structure to the format of the serialized data, resulting in poor version tolerance. Further, it cannot serialize to simple XML files.
This engine produces only XML files and is less powerful than other engines in saving and restoring a complex object graph (it cannot restore shared object references). It’s the most flexible of the three, however, in following an arbitrary XML structure. ASMX Web Services implicitly uses the XML serialization engine (Web Services implemented through WCF, however, uses the data contract engine).
The types that support the data contact and binary engines live in System.Runtime.Serialization
. The attribute-driven XML
serialization engine lives in System.Xml.Serialization
.
The assemblies into which C# programs compile comprise executable instructions
(stored as intermediate language or IL) and metadata, which describes the program’s
types, members, and attributes. Through reflection, you can inspect this metadata at
runtime, and do such things as retrieve attribute information, inspect types and
members, and dynamically invoke methods. With Reflection.Emit
, you can construct new code on the fly.
The types for reflection reside the following namespaces:
System System.Reflection System.Reflection.Emit
The window to most of the reflection data is a class called Type
; you can obtain an instance via C#’s typeof
operator or by calling GetType( )
on an object instance. The window to most assembly-related data is the Assembly
type.
The .NET Framework provides its own permission-based security layer, comprising code
access security and role-based security. Code access security allows you to both sandbox
other assemblies and be sandboxed yourself (limiting the kinds of operations that can be
performed). The central type for enforcing permission-based security is IPermission
.
System.Security System.Security.Permissions System.Security.Policy
The Framework also provides types for encryption (symmetric and public-key),
hashing, and data protection in the System.Security.Cryptography
namespace.
Multithreading allows you to execute
code in parallel. Central to multithreading is the Thread
class and synchronization constructs such as
exclusive locking (supported by C#’s lock
statement).
A free and extensive article on multithreading is available online at www.albahari.com/threading.
All types for threading are in the System.Threading
namespace.
The CLR provides an additional level of isolation within a process called an
application domain. A .NET process normally runs in a single
automatically created application domain. Creating additional application domains in the same process is useful for such
purposes as unit testing. The AppDomain
type is
defined in the System
namespace,
and it encapsulates access to application domains.
You can interoperate with native and Win32 code through the P/Invoke system. The
.NET runtime allows you to call native functions, register callbacks, map data
structures, and interoperate with native and COM data types. The namespace providing
this support is System.Runtime.
InteropServices
.
The Framework provides logging and assertion facilities through the Debug, Trace
, and TraceListener
classes in System.Diagnostics
. Also in this namespace is the Process
class for interacting with other processes, classes for writing to
the Windows event log, and types for reading/writing performance counters for
monitoring.
The .NET Framework provides three APIs for user-interfacebased applications:
System.Web.UI
)
For writing thin-client applications that run over a standard web browser
System.Windows
)
For writing rich-client applications that target the .NET Framework 3.0
System.Windows.Forms
)
For writing rich-client applications that target the classic Windows API, supported in all versions of the .NET Framework
In general, a thin-client application amounts to a web site; a rich-client application is a program the end user must download or install on the client computer.
Applications written using ASP.NET host under Windows IIS and can be accessed from almost any web browser. Here are its advantages over rich-client technologies:
Zero deployment at the client end
Clients can run a non-Windows platform
Updates are easily deployed
Further, because most of what you write in an ASP.NET application runs on the server, you design your data access layer to run in the same application domain—without limiting security or scalability. In contrast, a rich client that does the same is not generally as secure or scalable. (The solution, with the rich client, is to insert a middle tier between the client and database. The middle tier runs on a remote application server [often alongside the database server] and communicates with the rich clients via WCF, Web Services, or Remoting.)
Another benefit of ASP.NET is that it’s mature—it was introduced with the first version of .NET and has been refined with each subsequent .NET release.
The limitations of ASP.NET are largely a reflection of the limitations of thin-client systems in general:
A web browser interface significantly restricts what you can do.
Maintaining state on the client—or on behalf of the client—is cumbersome.
You can improve the interactivity and responsiveness, however, through client-side scripting or technologies such as AJAX; see http://ajax.asp.net/.
The types for writing ASP.NET applications are in the System.Web.UI
namespace and its subnamespaces, and they are packed
in the System.Web.dll assembly.
WPF is a rich-client technology new to Framework 3.0. Framework 3.0 comes installed on Windows Vista—and is available as a separate download for Windows XP SP2. Here are its benefits:
It supports sophisticated graphics, such as arbitrary transformations, 3D rendering, and true transparency.
Its primary measurement unit is not pixel-based, so applications display correctly at any DPI (dots per inch).
It has extensive dynamic layout support, which means you can localize an application without danger of elements overlapping.
Rendering uses DirectX and is fast, taking good advantage of graphics hardware acceleration.
User interfaces can be described declaratively in XAML files that can be maintained independently of the “code-behind” files—this helps to separate appearance from functionality.
Here are its limitations:
The technology is less mature than Windows Forms or ASP.NET.
Its size and complexity make for a steep learning curve.
Your clients must run Windows Vista—or Windows XP with Framework 3.0 or later.
The types for writing WPF applications are in the System.
Windows
namespace and all subnamespaces except for System. Windows.Forms
.
Windows Forms is a rich-client API that—like ASP.NET—is as old as the .NET Framework. Compared to WPF, Windows Forms is a relatively simple technology that provides most of the features you need in writing a typical Windows application. It also has significant relevancy in maintaining legacy applications. It has a number of drawbacks, though, compared to WPF:
Controls are positioned and sized in pixels, making it easy to write applications that break on clients whose DPI settings differ from the developer’s.
The API for drawing nonstandard controls is GDI+, which—although reasonably flexible—is slow in rendering large areas (and without double buffering, it flickers horribly).
Controls lack true transparency.
Dynamic layout is difficult to get right reliably.
The last point is an excellent reason to favor WPF over Windows Forms—even if you’re
writing a business application that needs just a user
interface and not a “user experience.” The layout elements in WPF, such as Grid
, make it easy to assemble labels and text boxes such
that they always align— even after language changing localization—without messy logic
and without any flickering. Further, you don’t have to bow to the lowest common
denominator in screen resolution—WPF layout elements have been designed from the outset
to adapt properly to resizing.
On the positive side, Windows Forms is relatively simple to learn and has a wealth of support in third-party controls.
The Windows Forms types are in the System.Windows.Forms
(in System.Windows.Forms.dll) and
System.Drawing
(in
System.Drawing.dll) namespaces. The latter also contains the GDI+
types for drawing custom controls.
ADO.NET is the managed data access API. Although the name is derived from ADO (ActiveX Data Objects), the technology is completely different. ADO.NET comprises two major components:
The provider model defines common classes and interfaces for low-level access to database providers. These interfaces comprise connections, commands, adapters, and readers (forward-only, read-only cursors over a database). The Framework ships with native support for Microsoft SQL Server and Oracle, and it has OLE-DB and ODBC providers.
A DataSet is a structured cache of data. It resembles a primitive in-memory database, which defines SQL constructs such as tables, rows, columns, relationships, constraints, and views. By programming against a cache of data, you can reduce the number of trips to the server, increasing server scalability and the responsiveness of a rich-client user interface. DataSets are serializable and designed to be sent across the wire between client and server applications.
LINQ to SQL sits above the provider layer, leveraging the lower-level connection and reader types. With LINQ to SQL, you avoid having to manually construct and parameterize SQL statements, reducing the volume of code in an application’s data access layer and improving its type safety. LINQ to SQL also partially avoids the need for DataSets through its object-relational mapping system. DataSets have some advantages, though, such as being able to serialize state changes to XML (something particularly useful in multitier applications). LINQ and DataSets can interoperate, however; for instance, you can use LINQ to perform type-safe queries over DataSet objects.
Windows Workflow is a framework for modeling and managing potentially long-running business processes. It targets a standard runtime library, providing consistency and interoperability. Workflow also helps reduce coding for dynamically controlled decision-making trees.
It is not strictly a backend technology—you can use it anywhere (an example is page flow in the UI).
Workflow is another part of the shipment of assemblies that came with the .NET
Framework 3.0, so like WPF, it leverages services that require the operating system
support of Windows Vista—or Windows XP after a Framework 3.0 installation. The Workflow
types are defined in (and are below) the System.WorkFlow
namespace.
WCF is the communications infrastructure new to Framework 3.0. WCF is flexible and configurable enough to make both of its predecessors—Remoting and (ASMX) Web Services—mostly redundant.
WCF, Remoting, and Web Services are all alike in that they implement the following basic model in allowing a client and server application to communicate:
On the server, you indicate what methods you’d like remote client applications to be able to call.
On the client, you specify or infer the signatures of the server methods you’d like to call.
On both the server and the client, you choose a transport and communication protocol (in WCF, this is done through a binding).
The client establishes a connection to the server.
The client calls a remote method, which executes transparently on the server.
WCF further decouples the client and server through service contracts and data contracts. Conceptually, the client sends an (XML) message to an endpoint on a remote service, rather than directly invoking a remote method. One of the benefits of this decoupling: clients have no dependency on the .NET platform or on any proprietary communication protocols.
WCF is highly configurable and provides the most extensive support for standardized messaging protocols, including WS-*. This lets you communicate with parties running different software—possibly on different platforms—while still supporting advanced features such as encryption. Another benefit of WCF is that you can change protocols without needing to change other aspects of your client or server applications.
The types for communicating with WCF are in, and under, the System.ServiceModel
namespace.
Remoting and ASMX Web Services are WCF’s predecessors and are almost redundant in WCF’s wake—although Remoting still has a niche in communicating between application domains within the same process.
Remoting’s functionality is geared toward tightly coupled applications. A typical example is when the client and server are both .NET applications written by the same company (or companies sharing common assemblies). Communication typically involves exchanging potentially complex custom .NET objects that the Remoting infrastructure serializes and deserializes without needing intervention.
The functionality of ASMX Web Services is geared toward loosely coupled or SOA-style applications. A typical example is a server designed to accept simple SOAP-based messages that originate from clients running a variety of software—on a variety of platforms. Web Services can only use HTTP and SOAP as transport and formatting protocols and applications are normally hosted under IIS. The benefits of interoperability come at a performance cost—a Web Services application is typically slower, in both execution and development time, than a well-designed Remoting application.
The types for Remoting are in or under System.Runtime.Remoting
; the types for Web Services are under System.Web.Services
.
CardSpace comprises the final new piece of the .NET 3.0 shipment. It is a token-based authentication and identity management protocol designed to simplify password management for end users. CardSpace builds on open XML standards, and parties can participate independently of Microsoft.
With CardSpace, a user can hold multiple identities, which are maintained by a third party (the identity provider). When a user wants to access a resource at site X, the user authenticates to the identity provider, which then issues a token to site X. This avoids having to provide a password directly to site X, and it reduces the number of identities that the user needs to maintain.
WCF allows you to specify a CardSpace identity when connecting through a secure HTTP
channel through types in the System.IdentityModel.Claims
and System.IdentityModel. Policy
namespaces.