.NET Framework Library 2 .NET Framework Library Overview Objectives This modules provides an overview about various aspects of the .NET framework libraries that are not covered elsewhere in the Microsoft .NET Developer Tools Readiness Kit. .NET Framework Library 3 Section 1: Introduction Section 1: Introduction We will start our tour through the .NET Framework Library by looking back at the status-quo of the Windows development libraries and will then take a look at the rationale for the .NET Framework library from there. Looking Back The Microsoft .NET Framework Library 4 .NET Framework Library Section 1: Introduction Looking Back Language Dependent Runtime Libraries In all of today’s development languages for the Windows platform, we find runtime libraries that are dependent on the development language that is used. When you want to concatenate two strings, there is a special way of doing that in Visual Basic, a special way to do that with the standards C-Runtime library and yet another way to do that with the C++ Standard Template Library. In addition, while most of the native platform APIs are easily accessible from C and C++, Visual Basic makes that a lot harder and there are many libraries that cannot be used with Visual Basic directly. These API holes are typically plugged with third part ActiveX controls, which not necessarily add value, but simply wrap APIs that are not immediately accessible from Visual Basic. In essence, this leads to a very inconsistent set of functions and component methods across languages and forces developers to relearn technology sets they already know. Discriminatory access to functionality In addition, these language-by-language runtime libraries are very discriminatory and have lead to a schism in the developer community. Visual Basic developers are often regarded as “no real programmers” by C++ developer, since their tools do not provide the same level of control as the C language family. Although that attitude is certainly childish, it roots in the discriminatory access to platform services, of which many cannot be directly used from languages like Visual Basic. .NET Framework Library 5 So, indeed, many advanced tasks do require the use of C and C++, but not because lack of developer skills to handle the platform complexity, but because their primary work-tool will not give them that option. Core functionality scattered all over Windows However, even if it would, developers would (and must do so today) have to seek their required functionality throughout a plethora of different ActiveX controls, Win32 APIs, Server SDKs and even in Internet Explorer. Although the documentation for most of the Microsoftsupplied APIs and components is (luckily) grouped nicely in the MSDN Library, it is much less convenient to find them and use or reference them. This can unfortunately turn from a mere inconvenience into a sheer nightmare when it comes to deployment. 6 .NET Framework Library Section 1: Introduction The .NET Framework Library One-stop, well-organized class framework Like some giant department store in the mid-Western United States, the .NET Framework Library offers “onestop” shopping. In reality, it’s more like the legendary library of Alexandria! Instead of books, the Framework Library warehouses classes that offer both the knowledge and means to “do things software.” The organization of the library is based on namespaces, which are essentially a means of categorizing and grouping logically or functionally similar classes together. The resulting namespace hierarchy makes working with the Framework intuitive, especially as the actual namespaces are so logically names. For example, classes that offer services and functionality most commonly needed elsewhere in the library, and essentially make up the “base system”, are contained in the “System” namespace. Likewise, classes that expose methods to work with data are found in System.Data, while the user interface classes for Web development are rooted in the System.Web.UI namespace. Microsoft has made an extraordinary effort to design and implement the Framework Library, and .NET in general, in as OS-independent a manner as possible. Microsoft, in conjunction with Hewlett-Packard and Intel, has even submitted an OS-independent subset to ECMA (http://www.ecma.ch), the same organization that standardized other Web technologies, such as the ECMA standardization of JScript, known as ECMAScript (ECMA262). The subset submitted for standardization includes most things covered here (form more information refer to http://msdn.microsoft.com/net/ecma). .NET Framework Library 7 Integrates all current Windows technologies The .NET Framework Library successfully integrates all current Windows technologies; everything is in one place and for all languages! You will find support for: Windows Forms, the .NET means of creating forms based applications; GDI+, the next iteration of GDI; support for printing; Web Forms, a means of developing Web based applications using a forms based paradigm; Web services; networking support; and support for Active Directory, WMI, MSMQ, Services, and more. 8 .NET Framework Library Section 2: The System Namespace Section 2: The System Namespace As you learned, the System namespace is a foundation of the .NET Framework library. While it is not technically the “root” of the Library namespace hierarchy (there actually is none), it is conceptually, as it provides the classes that are most common to the library as a whole. You will learn more about the classes found in the System namespace as you read on, as well as other Framework Library namespaces. Some topics you can expect to learn about are: System.Object The not-so-primitive "primitive" types String and text classes Dates, times and calendars System console support .NET Framework Library 9 Section 2: The System Namespace The Root of Everything .NET: Object Base class for each and every type In the .NET Framework, everything is an object – including even the simple data types, as you will learn. The granddaddy of them all, or root to this object hierarchy, is the Object class (a.k.a. System.Object). In fact, inheritance from System.Object is typically implicit. As you will find, all data types – both simple and complex – share this same base class helping make their behavior and the ways you use them consistent. Single base-class makes framework consistent This “object consistency“, if you will, is what helps makes the Framework itself consistent. System.Object enables you to use the collection classes of the Framework for everything. It also provides an intrinsic model for handling variant types that make programming less error prone, especially when compared to using COM’s VARIANT type. These positive affects are in a large part due to the strongly typed nature of the Framework Library and the exclusion of pointers and structures, System.Object is a reference type Value types (internally) inherit from ValueType While System.Object is a reference type, the value types found in the Framework are inherited not directly from Object but from the ValueType class. System.ValueType, however, is itself directly derived from Object, but overrides certain virtual methods, etc in a manner that makes the behavior of value types more logical – and practical. 10 .NET Framework Library Section 2: The System Namespace System.Object's Methods (1/2) Let us examine the six methods System.Object provides: Equals(); Finalize(); GetHashCode(); GetType(); MemberwiseClone(); and ToString(). bool System.Object.Equals(Object o) The Equal() method is used to test if an object is the same instance as another object. In other words, if you have an object A and an object B and you wish to see if they are the same exact instance – reference the same object instance – then you use the Equal method. For value types, this method is overridden to test for value identity (i.e. that two objects are of the same type and represent the same value). void System.Object.Finalize() By default the Finalize method does nothing. It is meant to be overridden by subclasses that wish to perform some type of cleanup before the Garbage Collector (GC) reclaims the Object. Note that the Finalize is not called until the object is garbage collected but it is not guaranteed to be run and if it runs it is not guaranteed to be run at any specific time. int System.Object.GetHashCode() Essentially, this method generates a hash value for the object that may then be used in any arbitrary hashing algorithm (or other manner), for example in a hash table (i.e. System.Collections.HashTable uses this method). It is recommended that you override the method to return good hashes; good hash distribution speeds up hash tables. Incidentally, the default implementation is Identitybased hashing. .NET Framework Library 11 Section 2: The System Namespace System.Object's Methods (2/2) System.Type System.Object.GetType() Conceptually, GetType returns the object’s type. In reality, it retrieves the Type object (System.Type) for the object's class. System.Type is an abstract class that is used to represent type declarations and provides the primary means to access metadata and acts is the entry point for .NET Reflection. System.Object System.Object.MemberwiseClone() MemberwiseClone() works through Reflection with any class to provide a means to creates a exact clone (copy) of "this" object. The method cannot be overriden. System.String ToString() The ToString method is designed to return a text representation of the current object. The default behavior is to return the fully qualified name of the class, but is designed to overriden so that you can return information more pertinent to your needs. This method is not designed for user messages, although it can be helpful when debugging. If your aim is user messages, use the IFormattable interface. 12 .NET Framework Library Section 2: The System Namespace The "Primitive" Types Traditionally perceived as "magic" or "special" Traditionally, primitive types, such as integers, have been perceived as “magic“. Indeed, in some object-oriented languages, such as Java, primitives are all but magic in that they are not objects themselves but more like a sheep in a wolf’s skin – they exhibit object-like behavior and expose means to work with them as if they were objects but they are not. In .NET, however, all is an object – that means that primitives are objects too. Actually, it is a very SmallTalk-like model in which "primitive" types are regular framework types. However, still exposed as language-intrinsic types While types in .NET are objects, the Framework still exposes the types as language-intrinsic types. For example, if you use C# you work with the following types: bool, int, long, string, double, float, etc. However, if you program in Visual Basic.NET, the Framework exposes the following types to you: Boolean, Integer, String, etc. "Primitives" are mostly value-types Although primitives are value-types, There is always an exception to every rule. With primitive types it is that all primitives are value-types except for System.String, which happens to be a reference type. "Primitive" Types are not so primitive anymore One major feature the Framework designers built in when they decided to make everything an object is that primitives are not so primitive anymore; they are fullfeatured classes with rich functionality! .NET Framework Library 13 Section 2: The System Namespace Integer Numerics The first stop on your journey down the primitives road is at the numeric types, beginning with integers. System.Int16, System.Int32, System.Int64 There are three types of integer types in the Framework: System.Int16; System.Int32; and System.Int64. As per the definition of an integer, these classes are used to contain and work with standard integer (whole number) types of varying magnitude (or length). While Int32 typically maps to the default language-mapped integer, there is also an Int16 and Int64 of 16-bit and 64-bit length respectively. The highest bit on all Int types is used as the sign bit. There are several framework interfaces implemented for integers: IFormattable: locale specific text formatting IConvertible: standard conversion into other core types IComparable: standard value-comparison with other objects The integers also benefit from the Parse() method, which provides rich from-text conversions. System.UInt16, System.UInt32, System.UInt64 The unsigned equivalents of Int16, Int32 and Int64 are: UInt16, UInt32 and UInt64. 14 .NET Framework Library Section 2: The System Namespace Floating Point Numerics (1/3) System.Single, System.Double Next stop on your numeric tour are the floating-point numbers: System.Single and System.Double. Both of these primitive types are based on the IEEE 754 floating point numbers used in most common programming languages. Internally the values are represented as fractions (narrowed values). Designed for scientific/technical and technical purposes, these types are not meant to represent business numerals, such as monetary values. System.Single: Single precision, 32-bit System.Double: Double precision, 64-bit Both types derive from the following interfaces: Formattable: Functionality to format the value of an object with local support; provides formatting that is usable by the end-user. IComparable: Generalized comparison interface, which is implemented by types that may be ordered. IConvertible: Describes a generalized type conversion and convenience methods. For example, converting an integer type to a string type. .NET Framework Library 15 Section 2: The System Namespace Floating Point Numerics (2/3) System.Decimal System.Decimal is designed for business numerals. Because of its 128-bit size, of which 28 bits are significant, it is ideal for large monetary amounts or other possibly large or precision sensitive values. To be more precise, the range of possible values is negative 79,228,162,514,264,337,593,543,950,335 through positive 79,228,162,514,264,337,593,543,950,335! Like their floating-point brethren Single and Double, the Decimal types implement the IFormattable, IComparable, and IConvertible interfaces. There are a few “special features” specific to the Single and Double types verses the Decimal type. System.Double, System.Single specials: Single and Double, for instance, support positive and negative infinity using the PositiveInfinity and NegativeInfinity constants on the class. Furthermore, both these types can represent not-a-number (NaN) values by using the NaN constant on class. Note that NaN always compares false. 16 .NET Framework Library Section 2: The System Namespace Floating Point Numerics (3/3) System.Decimal specials: Decimal, on the other hand, cannot represent NAN or infinity. However, it has static value manipulation methods such as Abs(d) and Negate(d) for getting the absolute value or the negated value of a decimal respectively. It also exposes the following methods: Truncate(d): Returns only the digits before the decimal. Floor(d): Rounds a decimal d to the next lowest whole number. Round(d,n): Rounds the decimal d to a specified number of decimal places n. The value of n must be between 0 and 28. Decimal also has several static arithmetic methods for performing math on two Decimal objects d1 and d2: Add(d1,d2), Multiply(d1,d2), Subtract(d1,d2), Divide(d1,d2), and Mod(d1,d2). All equivalent operators are defined for the class. .NET Framework Library 17 Section 2: The System Namespace Doing Numerics: System.Math What good would numerics be without math? The System namespace contains a class dedicated to common mathematical operations: System.Math. System.Math class mainly supports IEEE types Some operations for all numerics While System.Math is designed to mainly support IEEE types (i.e. floating or decimal numbers), it also provides methods that are common to all numbers: Abs(): Returns the absolute value of a number Log(): Returns the natural logarithm of a number Max(): Performs a comparison on two numbers, a and b, and returns the greater of the two. Min(): Converse of Max(). Round(): Rounds a number to the nearest specified parameter. Sign(): Returns the sign of a number. Operations: You may find it more interesting to view some of the operations grouped by “type”: Trigonometry: Sin(),Cos(), Tan(), Acos(), Asin(), ... Powers and Logarithms: Pow(), Log(), Sqrt(), ... Extremes: Min(), Max() Rouning: Floor(), Ceil(), Rint(), Round() 18 .NET Framework Library Section 2: The System Namespace System.String System.String is the cross-language string No framework would be complete without a string type, and .NET provides one with little left to desire! System.String is the cross-language string; it utilizes one storage method and exposes one API aimed at creating a unified means of handling strings! String is also localeaware and always Unicode. Fully-featured string handling capabilities String is a full-featured string class. It has methods to perform forward and reverse sub-string searches: IndexOf(), LastIndexOf(), StartsWith(), EndsWith(). It has methods to either strip or pad a string with white space (Trim(), PadLeft(), PadRight()), provides methods for range manipulation and extraction (Insert(), Remove(), Replace(), Substring(), Join(), Split()) and even ebables you to perform character casing and advanced formatting using ToLower(), ToUpper() and Format(). It is worth noting that the Format() method is much like C's printf but safe. .NET Framework Library 19 Section 2: The System Namespace More Strings: System.Text Namespace Although we are touring the System namespace, having encountered the String class it makes sense to take a short detour a string (or text) related namespace for a moment. The System.Text namespace contains classes representing various character encoding and conversions as well as providing helper classes for manipulating String objects and text in general. StringBuilder The StringBuilder class is a helper class that may be used in conjunction with a String object to manipulate a string. Because the StringBuilder uses a single buffer when manipulating a string, it is a super-efficient class for assembling large strings. String, in contrast performs copy operations when assembling a string from multiple literals or String objects. Encoders and Decoders Classes to represent and support character encoding and conversions including ASCII, UTF-8, UTF-7, and Windows Codepages. Some of the encoding/decoding supported include: The Unicode encoder for full UTF-16 compliant streams Encoder can write and decoder detect byte-order marks Supports big-endian and little-endian Unicode encoding 20 .NET Framework Library Section 2: The System Namespace Other Core Types System.Byte, System.SByte – Single byte numeric Some other types that are core to the Framework include System.Byte, which represents an 8-bit unsigned integer and provides an object representation of a byte primitive. Byte can contain an integer value in the range of 0-255. In contrast SByte is not compliant with the common language specification and may contain an integer value in the range of –128 to 127. System.Char – Single Unicode character System.Char represents a single Unicode character. System.Boolean – True or False logical value System.Boolean is the object representation of a Boolean value and contains the value of either true or false. System.Guid Windows programmers are familiar with GUID types. The Framework provides a class that encompasses this 128bit, universally unique identifier. The class has a built-in generator for new GUID values, System.Guid.NewGuid(), and includes intrinsic support for converting to and from strings. The "Nothings" “The nothings” are a special set of types: System.DBNull: Database-equivalent NULL type System.Empty: Like COM's VT_EMPTY System.Missing: Used with optional args .NET Framework Library 21 Section 2: The System Namespace Date and Time Support The Framework provides extensive support for dates and times through its classes and namespaces. System.DateTime class for dates and times The DateTime class provides virtually unlimited date values spanning 100 AD to 9999 AD and includes built in arithmetics, such as AddDays() and AddSeconds(). DateTime is also sophisticated enough to contain localeaware formatting and parsing. System.TimeSpan for durations Because a period of time is intrinsically different than time, the Framework provides the TimeSpan class. This class can represent arbitrary time spans and do so using an arbitrary unit by conversion. System.TimeZone for time-zone support Lastly, there is the TimeZone class, which is meant to address the increased need to support multiple time zones in solutions. It includes support for daylight saving time. 22 .NET Framework Library Section 2: The System Namespace Date and Time to the Max System.Globalization.Calendar namespace The System.Globalization namespace offers additional date and time related functionality through its Calendar class. The Calendar represents and works on time in divisions of days, weeks, months and years. Because there are different kinds of calendars in use globally, the Calendar class lets you work with several built-in types. Correct date expressions based on local calendars The .NET Framework has broad support for many local calendars besides the standard western calendar that is implemented in the GregorianCalendar class: JulianCalendar HebrewCalendar JapaneseCalendar KoreanCalendar ThaiBuddhistCalendar HijriCalendar Two-way 2/4 digit-year windowed conversion. The Calendar class contains a plethora of useful methods for working with time and dates from a “calendar centric view”: AddDays: Returns the DateTime object resulting from adding a fractional number of days to the specified DateTime. AddHours: Returns the DateTime resulting from adding a fractional number of hours to the specified DateTime. .NET Framework Library 23 AddMilliseconds: Returns the DateTime resulting from adding the specified number of milliseconds to the specified DateTime. AddMinutes: Returns the DateTime resulting from adding a fractional number of minutes to the specified DateTime. AddMonths: Returns the DateTime resulting from adding the specified number of months to the specified DateTime. AddSeconds: Returns the DateTime resulting from adding a number of seconds to the specified DateTime. AddWeeks: Returns the DateTime resulting from adding a number of weeks to the specified DateTime. AddYears: Returns the DateTime resulting from adding the specified number of years to the specified DateTime. Equals: (inherited from Object) Determines whether the specified Object is the same instance as the current Object. GetDayOfMonth: Returns the day-of-month part of the specified DateTime. GetDayOfWeek: Returns the day-of-week part of the specified DateTime. GetDayOfYear: Returns the day-of-year part of the specified DateTime. GetDaysInMonth: Overloaded. Returns the number of days in the specified month. 24 .NET Framework Library Section 2: The System Namespace The Console System.Console class for console I/O Although most applications today utilize a graphical user interface, text based applications are still developed and the ability to debug or quality assure (QA) applications during development using a console window is invaluable. To this end, the Framework offers a class specifically encompassing “all things console”: System.Console. Supports standard in, standard out, standard error The Console class supports the standard in, out and error that C/C++ users know so well. Writing to the console Writing to the console (or System.Console) is accomplished using either the Write() or WriteLine() method. Console.WriteLine( “Hello World” ); Console also supports String.Format syntax: Console.Write( "Snowwhite and the {0} dwarfs", 7); Reading from the console Reading from the Console is as easy as writing: Read(): Reads on characters ReadLine(): Reads the input until a carriage return or line-feed. .NET Framework Library 25 Section 2: The System Namespace Other System Goodies The .NET Framework is choc-full-of “goodies” easing your life as a developer and, best of all, you do not need to dig for these helper namespaces and classes. The following lists a few classes that exemplify this statement: System.URI class The URI class provides two-way parsing and construction of URIs. System.Random class The Random class is a random number generator. System.Radix class Radix class enables numeric base-system conversions (eg. Dec/Hex). System.Convert class Convert class is a one-stop place for core type conversions. 26 .NET Framework Library Section 3: Collection Classes Section 3: Collection Classes Section 3 introduces the collection classes. We start with an overview over the Array. Then we will examine the System.Collections namespace and have a look at the different kinds of collection interfaces and classes. .NET Framework Library 27 Section 3: Collection Classes The Array Only collection outside Collections namespace System.Array is a special collection class, because it is the only one outside the Collections namespace. It’s subordinated to the System namespace, represents the base class for all array types in the CLR, and provides properties and methods to manage arrays. This means that System.Array itself cannot be instantiated. If you want to create an instance of a managed array you have to specify the type of the array, which at least consists of the element type, the rank, and the lower bound(s). Depending on the given type an array is mapped to language-intrinsic arrays. Polymorphic, stores System.Object elements Since everything in .NET is an object and derives directly or indirectly from System.Object, System.Array stores System.Object elements. The elements of an array instance can be of any type, but all elements must be of the same type. You specify the element type at declaration time. Arbitrary number of dimensions, lengths The dimensions of the array are specified at creation time; in the moment you create the instance of the array (CreateInstance). It can have any arbitrary number of dimensions, which is referred to as the rank of the array. But once the array is constructed, the dimensions are fixed and cannot be changed. You even cannot add or delete elements. 28 .NET Framework Library The lower bound is the starting index of a dimension of an array. A multidimensional array can have different lower bounds for each dimension. Supports sorting System.Array has a public method Sort() which can be used to sort the elements of a one-dimensional array object. This method is overloaded and has a number of implementations. Sort() uses the interface IComparable that is implemented by the elements of the array (internal comparison). If you want to create your own logic for comparing elements, you can implement the IComparer interface (external comparison) and use another overloaded version of Sort(). Supports binary searches on sorted arrays Another thing to mention is that the Array class supports binary searches on a sorted one-dimensional array. The (overloaded) method is BinarySearch() and you can search, for example, through the whole array or through sections of it. Again you can use either the IComparable interface for internal or the IComparer interface for external comparison. .NET Framework Library 29 Section 3: Collection Classes Collection Interfaces (1/2) A collection class can implement one or more methods of one or more of the following interfaces. IEnumerable If you, for example, want to implement your own collection class and want to use it with the foreach statement, you must implement the IEnumerable interface. IEnumerable has only one method GetEnumerator() that returns an IEnumerator iterator. IEnumerator is the base interface for all enumerators. It supports one property Current to get the current element of the collection and two methods MoveNext() and Reset() to walk through the enumeration and set the enumerator to its initial position. Enumerators cannot be used to modify the underlying collection. ICollection (inherits IEnumerable) The ICollection interface is the basic collection interface and inherits from IEnumerable. It defines a set of methods common to all collections. The most important ones are Count(): takes the number of elements of the collection. CopyTo(): used to copy the ICollection elements to an one-dimensional array. 30 .NET Framework Library Section 3: Collection Classes Collection Interfaces (2/2) IDictionary (inherits ICollection) The IDictionary interface is a basic association container interface. It’s an implementation of a collection of key/value pairs. Methods of interest are Add() and Remove() to add and remove an entry to/from the IDictionary with the specified key, Contains() lets you check whether the IDictionary contains an entry with a certain key, and Clear() to remove all entries from the IDictionary. IList (inherits ICollection) The IList interface inherits from ICollection and IEnumerable. It is a basic list container interface – a base class for all lists. Methods of interest are the same as the ones explained for the IDictionary interface: Add() and Remove() to add and remove items to/from the list, Contains() lets you check whether the list contains a certain value, and Clear() to remove all items from the list. .NET Framework Library 31 Section 3: Collection Classes Collection Classes (1/3) System.Collections.ArrayList / ObjectList The classes System.Collections.ArrayList System.Collections.ObjectList are dynamic implementing the IList interface. and arrays Unlike the System.Array class they can grow and shrink in size, which means you can dynamically add or remove elements from a list. System.Collections.BitArray System.Collections.BitArray represents a super-compact array of bits. Each bit value is expressed as a Boolean. So, if a single bit is turned on/off (1/0) its value is “true/false”. System.Collections.HashTable The class System.Collections.HashTable is a fast hashtable implementing the IDictionary interface. It represents a collection of key/value pairs that are organized in a hash table using the hash value of the key. Because there is no Dictionary class implementing the IDictionary interface use the HashTable class if you want to work with key/value pair collections. System.Collections.SortedList Another implementation of the IDictionary interface is the System.Collections.SortedList class. This class organizes the key/value pair collection using the key (and not a hash value). 32 .NET Framework Library Entries in this collection can be accessed using either keys or indexes, but because of the sorting the access is slower compared to a HashTable. .NET Framework Library 33 Section 3: Collection Classes Collection Classes (2/3) System.Collections.Stack System.Collections.Stack is a simple queue of objects. It’s a stack implementation providing the methods Push() and Pop() to insert and remove objects at the top of the stack. It also provides the GetEnumerator() method to retrieve an (IEnumerable) iterator of the stack. System.Collections.Queue A little different from the Stack class the System.Collections.Queue class implements a first-in, first-out collection. The methods to add and remove objects are Dequeue() and Enqueue(). Dequeue() removes an object at the bow of the queue, while Enqueue() adds an object to the stern. Like all other collection classes System.Collection.Queue is fully enumerable. 34 .NET Framework Library Section 3: Collection Classes Collection Classes (3/3) System.Collections.NameObjectCollectionBase System.Collections.NameObjectsCollectionBase is an abstract class that is the base class for sorted key/value pair collections. The key is of type System.String and the value is of type System.Object. The entries can be accessed using either the hash value of the key (so, this is a hash table) or indexes. Unlike the HashTable class this class allows duplicate keys and keys that are null references. System.Collections.NameValueCollection System.Collection.NameValueCollection is an implementation of the NameObjectCollectionBase class. It supports a comma separated string list as the value for a single key entry. For example, the HttpRequest.Headers collection is a NameValueCollection of headers. .NET Framework Library 35 Section 4: I/O and Networking Section 4: I/O and Networking This section covers the classes for file and network I/O. Directories and Files Streams, Stream Readers and Stream Writers Isolated Storage Networking Support 36 .NET Framework Library Section 4: I/O and Networking Directories and Files Fully object-oriented way to explore the file system The “objectiveness” of the .NET Framework Library shows itself when you begin exploring the namespaces and classes that are used to work with directories and files. As a matter of fact, you are able to explore the file system in a fully object-oriented manner! System.IO.Directory represents a directory In the System.IO namespace contains all you will need to perform synchronous and asynchronous input and output (IO), be it using a stream or file. When working with directories and file, you will use the System.IO.Directory and System.IO.File classes for directories and files respectively. The Directory class methods to ease your directory navigation and complement the File class. Some of the methods include: GetDirectories([mask]): Returns an array of Directory objects containing the subdirectories that match the specified mask. GetFiles(…) Returns an array of File objects in the current directory that match a specified mask or string (file name). CreateSubdirectory( [directory_name] ): Creates a subdirectory to the current directory. System.IO.File represents a file Like the Directory class does for directories, the File class provides a clean, object-oriented way to work with files. Using the File class you can construct a file directly by providing a file name or fully qualified path (i.e. path plus .NET Framework Library 37 file name). Actually, if you supply only a file name, internally the fully qualified path is used, based on the current directory. Another way to obtain a file object is of course to use one returned from the GetFiles() enumeration of the Directory object. The main difference to pretty much all other file system APIs is that file directory entries and file objects are really mapped into a single class. Furthermore, the file system entries and stream access are unified. For instance, all the Open...() methods - i.e. Open(), OpenRead(), OpenWrite(), OpenText() - return System.IO.Stream. 38 .NET Framework Library Section 4: I/O and Networking Streams Abstract base-stream System.IO.Stream System.IO.Stream is an abstract class for reading and writing streams. Synchronous access is provided using the Read() & Write() methods, while full asynchronous support is achieved calling BeginRead() or BeginWrite() and passing a callback. The specified callback is invoked as soon as data is received. To complete an asynchronous call you should use the respective EndRead() or EndWrite() method. System.IO.FileStream If you wish to open and access files directly, you can use the FileStream object, which is the the actual The actual object type returned by File.Open() is a FileStream. System.IO.MemoryStream If you need to construct in-memory streams, you should use the MemoryStream class. .NET Framework Library 39 Section 4: I/O and Networking Stream Readers (1/2) Higher-Level access to Stream reading functions The stream readers provide a higher-level means of reading from streams. System.IO.BinaryReader The BinaryReader is designed for typed access to stream contents and has the read methods for most of the core data types: ReadInt16(); ReadBoolean(); ReadDouble(); etc. System.IO.TextReader TextReader is an abstract base class for reading strings from streams. It is the base class for the StreamReader and StringReader classes. Some of the methods include: Peek(): Peeks into the stream and returns the next character that will be read – but technically without actually reading the character (i.e. the reading position in the stream is not advanced). Read(): Reads the next character or characters (depending on the version used) from the stream. ReadBlock(): Reads characters from the stream to a character (array) buffer. ReadLine(): Reads one line form the input stream (i.e. it reads up until a carriage return or line-feed). ReadToEnd() Reads from the current position in the stream to the end and returns the result as one string. 40 .NET Framework Library Section 4: I/O and Networking Stream Readers (2/2) The StreamReader and StringReader classes implement the methods of their abstract base class, TextReader. System.IO.StreamReader (implements TextReader) The StreamReader is used to read characters from a byte stream in a particular encoding. The default encoding is UTF-8. System.IO.StringReader (implements TextReader) StringReader simulates stream input from a string. Like StreamReader, it implements the methods of its base class TextReader. .NET Framework Library 41 Section 4: I/O and Networking Stream Writers High-level access to Stream writing functions Complementing the read classes are corresponding write classes: BinaryWriter, TextWriter, StreamWriter and String Writer. Designed and implemented in a consistent manner as the readers, you will find them easily understood and straightforward to use. System.IO.BinaryWriter Designed to write types in binary form to a stream. Because there are over 15 strongly typed overloads for the Write() method they are not listed here, but some of the types handled include: bytes, signed bytes, long integers, booleans, and unisigned integers. System.IO.TextWriter Like its counterpart the TextReader, TextWriter is an abstract base class for writing strings to streams. In addition to specifying countless overloaded Write() mehthods, it contains corresponding WriteLine() methods. It is worth noting that some of these methods include placeholder-formatted strings. System.IO.StreamWriter (implements TextWriter) Supports writing strings to streams using a user specified encoding, such as the default UTF-8. System.IO.StringWriter Simulates stream-writes on an output string. 42 .NET Framework Library Section 4: I/O and Networking Isolated Storage Isolated storage is a new concept of the .NET Framework library that allows applications to allocate private storage area without worrying about the system’s file system layout. More precisely, Isolated Storage provides an isolated file system within the actual file-system that somewhat resembles the structured storage facility of COM in that it is implemented on a file whose location is managed by the common languages runtime. This enables .NET applications and downloaded .NET controls to persist data on disk although they may not have permissions to access the “regular” file system. Isolated Storage uses a different set of permissions. The storage area is fully isolated (or “sandboxed”) from the rest of the system and is subject to disk quotas so that each control or downloaded application may only use a certain amount of disk storage. Scoped, isolated virtual file system Isolated Storage can be scoped to a single user, which allows parallel isolated storage areas on a per-user basis for the same application or control. Isolated storage can also be scoped to the assembly, which means that all users share the same isolated storage area and the isolated storage is accessible only for a certain assembly. If you choose application domain scope, you can use isolated storage scoped to each logical .NET process (AppDomain), even if multiple application domains execute concurrently based on the same Assembly. Isolated storage is great for any type of temporary and short-lived persistent data, which is scoped to a certain application. There are no file-name clashes with other .NET Framework Library 43 applications to look out for and applications don’t need to worry about the location and/or access rights for the “TEMP” directory on the local drive. As stated before, Isolated storage is entirely sandboxed, so that applications using isolated storage can use the local hard drive in a very controlled manner without compromising overall system security. Storage location managed by runtime system The storage locations for Isolated storage and the quotas are automatically managed by the runtime system. Global settings for the isolated storage subsystem can be configured using the standard .NET configuration mechanisms using enterprise-level, machine-level or application-level configuration files. System.IO.IsolatedStorage.IsolatedStorageFile The IsolatedStorageFile class is the container for IsolatedStorageFileStreams and represents a virtual file system. You can create a new storage file (or access an existing one) through the static class methods GetStore, GetUserStoreForAssembly and GetUserStoreForDomain. The IsolatedStorageFile lets you manage files (file streams to be precise) and an entire directory structure. [...] IsolatedStorageFileStream The IsolatedStorageFileStream represents a file within an isolated storage directory and behaves exactly like the file streams that you work with using the regular file system classes. 44 .NET Framework Library Section 4: I/O and Networking The Net in .NET: System.Net .NET wouldn’t deserve the name .NET without comprehensive support for networking. Underneath the high-level technologies like WebServices or ASP.NET act the networking classes that are contained in the System.Net namespace. System.Net contains all network protocol support The namespace System.Net contains the complete support for all network protocol options in the .NET Framework. This covers both, low-level network access through sockets and application-level protocols like HTTP. Low-level support for IP sockets and IPX The socket library in System.Net.Sockets supports various protocols that run on top of the Internet Protocol (IP) and has explicit helper classes for TCP and UDP. The Novell network protocol IPX is also supported. Application level protocol implementations (HTTP) The support for application level protocols and access to essential parts of the networking infrastructure (such as the Domain Name Services, DNS) resides directly in the System.Net namespace. The System.Net namespace also contains a complete client and server (!) infrastructure for HTTP and allows plugging in your own protocol handlers. Authentication methods for HTTP For HTTP, System.NET has full support for Basic and Digest authentications compliant to RFC2617 and also supports the Windows NTLM authentication scheme. .NET Framework Library 45 Full cookie support for HTTP The HTTP client and HTTP server implementation also has full support for sending and evaluating HTTP cookies. 46 .NET Framework Library Section 4: I/O and Networking Request and Response Classes System.Net.WebRequest class The core of the application-level protocol support through which you can access HTTP and which also allows you to create and plug-in your own protocols, is made available through the WebRequest class. The WebRequest class is an abstract base class, which provides a basic infrastructure for creating Request/Response interactions based on any applicationlevel protocol. The .NET Framework supplies a standard implementation for HTTP and HTTPS through the HttpWebRequest class. Create requests through WebRequest.Create() Web requests are created through the Create() method on the WebRequest class, providing an HTTP URL. Plug in new protocol handlers with RegisterPrefix() The HttpWebRequest implementation is automatically registered with the WebRequest infrastructure using the protocol prefixes “http” and “https”. If you want to use your own protocol implementations with the WebRequest infrastructure, you can hook in your protocol handlers by registering a custom protocol prefix together with an implementation of the IWebRequestCreate interface. Request can be populated through stream Each implementation of a web request class returns a stream (System.IO.Stream) that allows you to provide the data to be sent in the request. You can obtain the stream reference by calling WebRequest.GetRequestStream(). .NET Framework Library 47 Request is executed on GetResponse() With the HTTP protocol family, the request is sent once you request the result by calling the WebResponse.GetResponseStream() method. The response stream (also an instance of System.IO.Stream) contains the entire result as received from the server side. 48 .NET Framework Library Section 4: I/O and Networking Protocol Support Classes Manage connectivity through ServicePoint To limit the number of outbound sockets to be established and make use of advanced HTTP features like persistent connections to optimize client/server interaction, .NET manages connections through the ServicePoint infrastructure. For web requests, all endpoints are managed by the ServicePointManager and ServicePoint classes and enable that multiple web requests that target the same endpoint will reuse or share an existing endpoint connection if present, instead of reopening a new socket for each request. The ServicePoint class will also let you query SSL certificate information and lets you control various connection parameters that are common to all connections to a particular host. Shared service points allow for an overall greater scalability of your application, because they efficiently manage the limited number of sockets that are available for the entire system. System.Net.EndPoint information in ServicePoint The end points (connection targets) of service points are implemented on top of the protocol agnostic EndPoint class, which has specialization for the Internet Protocol (IP) in System.Net.IPEndPoint and for Novell IPX in System.Net.IpxEndPoint. System.Net.DNS The System.Net.DNS class provides access to DNS name-servers and gives easy access to name resolution through the GetHostByName() and Resolve() methods. .NET Framework Library 49 The DNS class uses the DNS server information configured in the system’s default IP protocol stack. 50 .NET Framework Library Section 4: I/O and Networking IP Sockets The socket library that is implemented in System.Net.Sockets is the reincarnation of the Berkeley sockets library on the .NET platform. Berkeley sockets had been adopted for Windows with the WinSock API and now found its way into the .NET Framework in a modernized and object-oriented, but still very familiar form. System.Net.Sockets.Socket for raw sockets The Socket class within the System.Net.Sockets namespace groups all socket related functions in a single class. To create a new socket, you simple create an instance of the socket class, connect the socket with Connect() and can then use the familiar Send() and Receive() methods to send or read data from the socket. Socket.Connect() connects to EndPoint The Connect() function connects to an EndPoint representing a TCP, UDP, IP multicast, IPX or other protocol binding. Socket.Bind() and Socket.Listen() create listener If you need to implement a server, you can Bind() the socket to a specific endpoint and enter listening on that endpoint using the Listen() method, just as you would do it with the plain WinSock API or Berkeley sockets on Unix. High-Level wrappers for TCP, UDP In addition to the low-level socket APIs that are available on the Socket class, .NET adds higher-level wrappers for plain sockets that make low-level network connections truly easy to use: .NET Framework Library 51 The TcpClient and UdpClient classes wrap the socket functionality and provide access to a NetworkStream class instance that acts exactly like a local file stream and lets you use the StreamReader and StreamWriter infrastructure on a networking socket. The TcpListener class is a higher-level implementation for a TCP server process that wraps the socket class. TcpListeners are started with Start() and stop listening with Stop(). The method Accept() will block until a client is connected and will then return a socket that you can use to communicate with the client. That socket can then be passed to a new NetworkStream object, which can be served on a different thread. 52 .NET Framework Library Section 5: Process Management Section 5: Process Management Process control A Process component provides access to an executable running on a computer. A process, in the simplest terms, is a running application. Threading support A thread is the basic unit to which the operating system allocates processor time. A thread can execute any part of the process code, including parts currently being executed by another thread. The framework provides a set of classes to create and monitor threads as well as synchronizing mechanisms. .NET Framework Library 53 Section 5: Process Management Processes System.Diagnostics.Process class This class provides access to processes can be local or remote. processes. These Allows creating/monitoring other processes The Process class is a useful tool to monitor applications. Using the Process class, you can obtain a list of processes that are running, or start a new process. A Process class is used to access system processes. Once a Process class has been initialized, it can then be used to obtain information about the running process, such as the set of threads, loaded modules (.dll or .exe's), or performance information such as the amount of memory the process is using, in addition to all information that is presented through the Task Manager. Once the Process class has obtained information about the associated process, it will not try to obtain it again until you call the Refresh method. A system process is identified uniquely on the system by its process ID. In addition, a process, like many Windows resources, has a handle by which it identifies itself, but which may not be unique on the computer. A handle is the generic term for an identifier to a resource. The process handle, accessed through the Handle property on the Process class, is persisted by the operating system even when the process has exited so that you can get administrative information about the process, like the ExitCode (usually, 0 for success or a non-zero error code) and the ExitTime. 54 .NET Framework Library Handles are an extremely precious resource, so leaking handles is more virulent than leaking memory. The operating system will only release the handle and associated data when there are no longer any handles to the process on the system, when the HandleCount is 0. Process.Start() equivalent to Win32 ShellExecute The Process class implements four ways to start a process. The first is an instance method, that simply starts the process that is described by the StartInfo property of that instance. The procedure is creating an instance of Process, setting the StartInfo data accordingly and then calling Start() on that Process instance. The other three ways are static methods of the Process class, that take different parameters: A ProcessStartInfo object, a string specifying the name of a document or application file or two strings specifying the name of an application and a set of command line arguments. The StartInfo property or parameter also serves for specifying a command verb like “print” or “open”. This action is immediately executed after the process has started and documents are loaded. Supports waiting for termination (WaitForExit) Calling WaitForExit without any parameter suspends execution of the current thread and waits for termination of the monitored process. A registered event handlers for the Exited event is called upon termination of the process. It is possible to wait for termination only for a specified time interval. The WaitForExit method with an interval as parameter returns true, if the process actually terminates, and returns false, if that interval elapses without termination of the process. Explicit termination supported in two ways Whenever you use Start to start a process, you must be sure to close it or you risk losing system resources. You close processes in a more cooperative way using CloseMainWindow or with a final and uncompromising way using Kill. CloseMainWindow is used to close processes that contain a graphical interface, while Kill must be used for non-graphical applications that do not have a message pump to handle a windows Close request. Calling CloseMainWindow revokes all running message loops on all threads and closes all windows. The request .NET Framework Library 55 to exit the process by calling CloseMainWindow does not force the application to quit. It can ask for user verification to perform the shutdown, or it can refuse shutdown if the application is running a macro. To force a shutdown, use Kill. The behavior of CloseMainWindow is identical to that of a user closing an application's main window using the system menu. Hence, the request to exit the process by closing the main window does not force the application to quit immediately. Note Currently, all processes started using a Process class open in a command window. They contain a message loop and you can attempt to close them using CloseMainWindow. This will change in a future release. Depending on how the non-graphical interface process is coded, CloseMainWindow could fail and Kill could be necessary in order to stop the process. 56 .NET Framework Library Section 5: Process Management System.Threading.Thread Every .NET application is fully multi-threaded One or more threads run in an AppDomain. An AppDomain is a runtime representation of a logical process within a physical process. A thread is the basic unit to which the operating system allocates processor time. Each AppDomain is started with a single thread, but can create additional threads from any of its threads. In contrast to programming under COM there are no more threading models like single or multi apartment threading. When using COM Interop however, developers need to be aware of the threading characteristics of the COM classes they’re using in order to write the most efficient code. There is definitely a trade-off for this simple and efficient model: the programmer is responsible for synchronization: no automatic access synchronization is accomplished by the runtime. System.Thread represents a system thread Creating a new instance of a System.Threading.Thread object can create new managed threads. The constructor for System.Threading.Thread takes, as its only parameter, a Thread Delegate. The delegate references a method in some class, that serves as the entry point of the thread. This method itself cannot be declared having any parameters. The thread’s launch-state is set on the object hosting the delegate’s method. .NET Framework Library 57 ThreadPool implicitly created for each process There are many applications that create threads that spend a great deal of time in the sleeping state waiting for an event to occur. Other threads may enter a sleeping state only to be awakened periodically to poll for a change or update status information. Thread pooling enables you to use threads more efficiently by providing your application with a pool of worker threads that are managed by the system. One thread monitors the status of all wait operations queued to the thread pool. When a wait operation has completed, a worker thread from the thread pool executes the corresponding callback function. The thread pool for the process is created the first time you call ThreadPool.QueueUserWorkItem, or when a timer or registered wait operation queues a callback function. 58 .NET Framework Library Section 5: Process Management Creating Threads This sample shows how a thread is created, started and how the original and the newly create thread are synchronized again. The class Pulsar implements the thread’s entry point method Run(). An object of this class must be created first. Pulsar pulsar = new Pulsar(); A new TreadStart object is created using the Pulsar.Run() method as entry point. ThreadStart threadStart = new ThreadStart(pulsar.Run); The actual thread object is created with the ThreadStart as parameter and started right away. Thread thread = new Thread(threadStart); thread.Start(); While the newly created thread is executing, the original thread can perform any other task, especially create some other threads. When the original thread is done with it’s work and wants to synchronize again with the new thread, it just executes the Join() method on that new thread and execution is halted until the new thread terminates, that is the entry point method returns. thread.Join(); .NET Framework Library 59 Section 5: Process Management Thread Synchronization Monitor System.Threading.Monitor class The System.Threading.Monitor class provides the means for synchronization of threads, that are very similar to the Win32 critical sections method. It is used to form a synchronized block in a way, that only a single thread can modify a certain object. Monitors are used within the code of the threads that are to be synchronized. The two static methods Enter and Exit are used to form the entry and exit of the block. The object to be accessed in a synchronized matter is given as a parameter. In our sample, it is the object implementing the thread’s method itself, but it can be any instantiated managed object. Only one thread can be active in this block, i.e. modify the member internalState (in that sample) at a time. C# has a special keyword lock that is mapped internally to a Monitor Enter/Exit block. The Monitor class supports a Wait/Pulse coordination model. This allows for more advanced control of execution. Within a synchronized block a thread can call the static method Wait() to pause execution at that point. The executing thread is put into a waiting queue. If another thread is waiting at the block’s entry or just arriving it is allowed to enter the block. Threads in the waiting queue are halted until another thread executes the Pulse method. Then the next thread in the waiting queue is moved to the ready queue. As soon as the thread that invoked Pulse releases the lock, the next thread (if there is one) in the ready queue is allowed to take control of the lock. 60 .NET Framework Library Section 5: Process Management More Threading Synchronization with WaitHandle The WaitHandle class represents all synchronization objects in the runtime that allow multiple wait. This object is a singleton that is created by the runtime. It encapsulates Win32 synchronization handles and is subclassed for threads, mutexes, events etc. Mutexes are in contrast to synchronization blocks single points of synchronization. WaitOne, WaitAll and WaitAny can be used to request ownership of the mutex or a group of mutexes respectively. The state of the mutex is signaled if no thread owns it. The thread that owns a mutex can specify the same mutex in repeated wait function calls without blocking its execution. It must release the mutex via ReleaseMutex as many times to release ownership. A ManualResetEvent object represents an event object whose state can be manually set and reset. The state of a manual-reset event object remains signaled until it is set explicitly to the nonsignaled state by the Reset method. Any number of waiting threads, or threads that subsequently begin wait operations for the specified event object by calling one of the wait functions, can be released while the object's state is signaled. AutoResetEvent remains signaled until a single waiting thread is released, at which time the system automatically sets the state to nonsignaled. If no threads are waiting, the event object's state remains signaled. .NET Framework Library 61 Threading Timers for timed callbacks The System.Threading.Timer class is used to set up a callback via a delegate that is invoked on it’s own thread after a specified time interval has elapsed. The timer is set to the signaled state when its specified due time arrives. Any thread with a handle to the timer can use one of the wait functions to wait for the timer state to be set to signaled. Interlocked class for lightweight locking The Interlocked class provides the mechanism for synchronizing access to an integer variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory. The Increment and Decrement methods combine the operations of incrementing or decrementing the variable and checking the resulting value. This atomic operation is useful in a multitasking operating system, in which the system can interrupt one thread's execution to grant a slice of processor time to another thread. Without such synchronization, one thread could increment a variable but be interrupted by the system before it can check the resulting value of the variable. A second thread could then increment the same variable. When the first thread receives its next time slice, it will check the value of the variable, which has now been incremented not once but twice. The interlocked variable-access functions protect against this kind of error. The Exchange method atomically exchanges the values of the specified variables. The CompareExchange method combines two operations: comparing two values and storing a third value in one of the variables, based on the outcome of the comparison. 62 .NET Framework Library Section 6: Advanced Services Section 6: Advanced Services In the final section of this overview on the .NET Framework library we look at some of the advanced services available in the Library. This section covers the classes and namespaces that provide access to Windows 2000 services like Active Directory or Windows Management Instrumentation and how your .NET applications can report errors, warnings or status information via the Windows event logging facility. Windows 2000 Services Diagnostics and Profiling .NET Framework Library 63 Section 6: Advanced Services Windows 2000 Services System.Management The System.Management namespace provides access to the Windows Management Instrumentation (WMI) system in Windows 2000. The WMI implementation in the .NET Framework provides a completely object-oriented view on WMI classes and is much more elegant and much more intuitive than the original WMI API. You can access WMI objects using the ManagementObject class and can manage WMI classes using the ManagementClass class. If you need to query for objects you can easily run WQL queries using the ManagementObjectSearcher class. System.Messaging The System.Messaging namespace provides access to the Microsoft Message Queue services. In addition to the MessageQueue class that you would expect to be in a message queue centric namespace, System.Messaging provides a complete message formatter infrastructure that allows you to create and parse queued messages in binary format (.NET native formats), XML and a specialized “ActiveX” formatter that is compatible with the COM data-types and stream formats so that .NET applications and COM applications can seamlessly exchange information through MSMQ. In addition, the namespace provides filtering and enumeration facilities which allow you to pick only those messages from the queue that satisfy a certain set of criteria. Using this you can share a message queue among several specialized worker threads. 64 .NET Framework Library System.DirectoryServices The DirectoryServices namespace is the .NET Framework’s gateway to access the Active Directory infrastructure. The DirectoryEntry class gives you here very easy access to directory entries (and schema entries) and the DirectorySearcher lets you search the directory. The properties of a DirectoryEntry are available on the Properties collection and due to the common type system automatically provided in the correct, native data type. System.ServiceProcess If you want to run .NET managed applications as Windows NT or Windows 2000 service processes, you don’t need to look any further than the ServiceBase baseclass located in the Windows ServiceProcess namespace. ServiceBase provides all of the essential plumbing and entry points to your .NET based process and all you need to do is to override the “OnStart” method to start up your service process and the “OnStop” method to shut down all listeners and worker threads gracefully. To deploy your services process you can use the “InstallUtil.exe” utility provided with the .NET Framework. This utility will trigger the ServiceInstaller class that registers your services with the system. ServiceBase provides a default implementation, but you can also provide a customized ServiceInstaller for a more specialized installation, including running services on specific user accounts or installing services that are manually started or initially disabled. The default installer will install the service to start automatically under the local system account. .NET Framework Library 65 Section 6: Advanced Services Windows 2000 Event Log System.Diagnostics.EventLog class The EventLog class in the System.Diagnostics namespace provides access to the Windows NT and Windows 2000 event log and lets you both read from and write to the event log. Reading event logs The static method EventLog.GetEventLogs() lets you query all logs on a specific machine and returns them as an array of EventLog objects. Each instance of EventLog represents a single log, such as the Application, Security or System log. The EventLog.Log property indicates the type of the event log. The EventLog.Entries property retrieves all entries for a log returning an EventLog.EventLogEntryCollection object that contains EventLogEntry elements. Instead of polling for event log entries you can also install an event handler with the EventLog class that will be triggered each time a new entry is added to the log. Writing event logs Just as with the unmanaged event log APIs, writing to the event log requires registering an event log source. Registering event sources is done through the static method CreateEventSource(). This method registers the application and associates it with a certain event log. All calls to WriteEntry() on the EventLog class with a “Source” property matching the registered source string will then be written to the specified log. Note that the external message tables of the Win32 event log API are not explicitly supported or wrapped by .NET. 66 .NET Framework Library Section 6: Advanced Services Other Diagnostic Services In addition to the event log, .NET provides quite a few more diagnostics services (including, of course, the debugger interfaces). The most useful for your applications might be the following: System.Diagnostics.PerformanceCounter The PerformanceCounter class will let you access existing performance counters on the Windows NT and Windows 2000 platforms to query them and allows you to create, register and update your own global performance counters. System.Diagnostics.StackTrace Whenever your application gets caught in an unexpected situation from which you either cannot recover gracefully and need to provide diagnostic information for support log files or where you need current information about which code has been calling your code for another reason, you can create an instance of the StackTrace class, which will create a stack trace reflecting the call stack of the present location within your application. The StackTrace is a collection of StackFrame instances that each include the full name and signature of the calling method as available through Reflection and the IL-based “instruction pointer” from where the call was executed. Each stack frame also contains a reference to the implementing source code file and line, if debug information is present in the metadata. System.Diagnostics.Trace The Trace class allows code instrumentation with diagnostic output. You can use the Trace class to .NET Framework Library 67 instrument your code with diagnostics and “health watch” information that is available at runtime through registering TraceListeners. VisualStudio.NET automatically registers such handlers to produce output for the “Output” window in the Debugger and therefore has tracing enabled at all times. Using a switch on the compilers you can entirely disable any code-generation for calls to the Trace class for your release versions, so that you can leave your code fully instrumented at all times. 68 .NET Framework Library Summary Summary Of course, this module could only provide a very highlevel overview on the wealth of the .NET class universe and we couldn’t do much more than highlighting a number of classes that you may want to look up in the .NET Framework library documentation. The .NET framework is huge and there is a lot to learn – the pleasant aspect is that it is all in one place and nicely organized into a hierarchy of namespaces instead of cluttered all over the system with a plethora of different API implementation technologies and implementation styles. Everything is based on System.Object All classes are based on System.Object, whose methods we covered and highlighted. Rich set of foundation classes The object-ness of all classes enables the .NET Framework to provide rich, fully polymorphic collection and utility classes that work with any type and provide solutions for most of the common developments tasks. Comprehensive set of general-purpose, object-oriented classes for Networking and I/O Networking and file-system access in .NET is now easier than ever before. The .NET Framework provides a fully object-oriented way to navigate and access file-system objects and provides a flexible and extensible networking infrastructure. .NET Framework Library 69 Great access to Windows 2000 services Windows 2000 and Windows NT services, which contribute to the success of the Windows 2000 platform are fully accessible from .NET through clean, objectoriented and redesigned programming interfaces. Rich diagnostic and monitoring facilities Just because server applications run invisibly, they don’t need to run silently. With the built-in diagnostic and monitoring facilities, you can provide information from within your .NET applications for complete runtime behavior transparency and enhanced maintainability.