XML documentation enables you to include syntax, help, and examples for the classes you create at the source - code level.. For example, the following code shows how to place XML docume
Trang 1A similar method is used to set the Inherited property If a custom attribute has properties, then you
can set these in the same manner One example might be to add the name of the person who fixed
the bug:
public readonly string BugNumber;
public readonly string Comments;
public readonly string Author;
return string.Format (“BugFix {0} by {1} : {2}” ,
BugNumber , Author , Comments);
}
This adds the Author field and an overridden ToString() implementation that displays the full details
if the Author field is set If the Author property is not defined when you attribute your code, then the
output from the BugFix attribute just shows the bug number and comments The ToString() method
would be used to display a list of bug fixes for a given section of code — perhaps to print and file away
somewhere Once you have written the BugFix attribute, you need some way to report the fixes made
on a class and the members of that class
The way to report bug fixes for a class is to pass the class type (again a System.Type ) to the following
DisplayFixes function This also uses reflection to find any bug fixes applied to the class, and then
iterates through all methods of that class looking for BugFix attributes:
public static void DisplayFixes (System.Type t)
{
// Get all bug fixes for the given type,
// which is assumed to be a class
object[] fixes = t.GetCustomAttributes (typeof (BugFixAttribute) , false);
Console.WriteLine (“Displaying fixes for {0}” , t);
// Display the big fix information
foreach (BugFixAttribute bugFix in fixes)
Console.WriteLine (“ {0}” , bugFix);
// Now get all members (i.e., functions) of the class
foreach (MemberInfo member in t.GetMembers (BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Static))
{
// And find any big fixes applied to these too
object[] memberFixes = member.GetCustomAttributes(typeof(BugFixAttribute)
, false);
if (memberFixes.Length > 0)
{
Trang 2Console.WriteLine (“ {0}” , member.Name);
// Loop through and display these
foreach (BugFixAttribute memberFix in memberFixes) Console.WriteLine (“ {0}” , memberFix);
} }}
The code first retrieves all BugFix attributes from the type itself:
object[] fixes = t.GetCustomAttributes (typeof (BugFixAttribute),false);
These are enumerated and displayed The code then loops through all members defined on the class, by using the GetMembers() method:
foreach (MemberInfo member in t.GetMembers ( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))
After getting all members, you loop through these, finding any BugFix attributes associated with the particular member, and output these to the console To output a list of bug fixes for a given class, you just call the static DisplayFixes() method, passing in the class type:
BugFixAttribute.DisplayFixes (typeof (MyBuggyCode));
For the MyBuggyCode class presented earlier, this results in the following output:
Displaying fixes for MyBuggyCode BugFix 101 : Created some methods DoSomething
BugFix 2112 : Returned a non-null string BugFix 38382 : Returned OK
.ctor BugFix 90125 : Removed call to base()
If you wanted to display fixes for all classes in a given assembly, you could use reflection to get all the types from the assembly, and pass each one to the static BugFixAttribute.DisplayFixes method
Trang 3AttributeUsage.Inherited
An attribute may be defined as inheritable by setting this flag when defining the custom attribute:
[AttributeUsage (AttributeTargets.Class,
Inherited = true)]
public class BugFixAttribute { }
This indicates that the BugFix attribute will be inherited by any subclasses of the class using the
attribute, which may or may not be desirable In the case of the BugFix attribute, this behavior would
probably not be desirable, because a bug fix normally applies to a single class and not the derived
classes
Suppose you have the following abstract class with a bug fix applied:
[BugFix(“38383”,”Fixed that abstract bug”)]
public abstract class GenericRow : DataRow
If you created a subclass from this class, you wouldn ’ t want the same BugFix attribute to be reflected in
the subclass — the subclass has not had that fix done on it However, if you were defining a set of
attributes that linked members of a class to fields in a database table, then you probably would want to
inherit these attributes
Armed with the knowledge you now have about custom attributes, you can probably think of several
places where adding extra information to assemblies is useful You could take the BugFix attribute
defined here and extend it too — one example would be to define the version number of the software
that the bug was fixed in That would enable you to display to end users all bugs fixed for a given
version of your application simply by using reflection to find the BugFix attributes and then checking
the version number of that fix against the versions that the end user has asked to see
This would also be great for producing documentation at the end of a product cycle to list all fixes made
in the latest version Obviously, you have to rely on the developers to add in these attributes, but it could
be made part of the code review cycle to ensure that all fixes were documented within the code
Summar y
This chapter described what attributes are and discussed some of the attributes defined within the NET
Framework There are many more attribute classes within the framework, and the best way to find out
what they are used for is to look through the NET Framework SDK documentation To find all attributes
in an assembly, just load it into Reflector, browse for the System.Attribute class, and then display the
derived types You may be surprised at just how many attributes are defined within NET
Trang 4In this chapter, you learned about the following attribute - related topics:
Using the Conditional attribute to exclude debugging code from release mode binaries Using the Obsolete attribute to revise libraries over time
How serialization uses attributes to specify what should and what should not be serialized How to delay - sign an assembly
How to create custom attributes
Attributes are a powerful way to add extra, out - of - band information to your assemblies You can create your own attributes to add extra information to your classes as appropriate This chapter described how
to create a BugFix attribute, which could be used to provide a link between the source code that was fixed and the bug originally raised by an end user There are many other uses of attributes — and you are encouraged to look into the NET Framework for other attribute classes
Trang 631
XML Documentation
Up to this point in this book, you ’ ve seen the entire C# language and a great many things you can
do with it, including both Web and Windows programming Along the way, you ’ ve seen and made extensive use of the IntelliSense feature in Visual Studio This helpful tool dramatically reduces the amount of typing you have to do, because it suggests keywords, type names, variable names, and parameters as you type It also makes it easier to remember what methods and properties you have at your disposal and often tells you exactly how to use them
However, the classes you have made have suffered slightly here While the classes and member names are suggested for you, no handy hints pop up telling you how to do things To achieve the
kind of behavior that you see with the NET Framework types, you need to use XML
documentation XML documentation enables you to include syntax, help, and examples for the
classes you create at the source - code level This information may then be used to provide IntelliSense information for Visual Studio as discussed previously, but there are other possibilities
You can use XML documentation as a starting point for full, MSDN - link documentation of your projects You can also style the XML documentation using XSLT to obtain instant HTML documentation with very little effort You have seen in earlier chapters just how versatile XML is, and you can use all of its power in the development and production life cycle of your applications
Documentation is particularly important when you are working as part of a team, as it enables you
to show exactly how your types work It can also be very useful to end users if you are creating an SDK or similar product where you expect people to use your classes from their code Having the facility to create this documentation built into the tool you use to develop code is a very powerful feature Although adding XML documentation to your code can be a time - consuming process, the result is well worth it Dropping text in as you develop can make things easier in the long run and provide you with a handy quick reference that will help to avoid confusion when the amount of classes in your project starts getting out of hand
In this chapter, you will learn two main things:
How to add and view basic XML documentation How to use XML documentation
❑
❑
Trang 7Adding XML Documentation
Adding XML documentation to your code is a remarkably simple thing to do As with attributes, which
you examined in the previous chapter, you can apply XML documentation to any type or member by
placing it on lines just before the member XML documentation is added by using an extended version of
C# comment syntax, with three front slashes instead of two For example, the following code shows how
to place XML documentation in a source code file for a class called MyClass , and a method of that class,
XML documentation cannot be applied to namespace declarations
Typically, XML documentation will span multiple lines and be marked up by using the XML
Here, < XMLDocElement > is one of several available elements, and may contain nested elements, some
of which use attributes to further specify functionality Note that the /// parts of the lines of code
containing XML documentation are completely ignored and treated as whitespace They are necessary to
prevent the compiler from thinking that the lines of documentation can be interpreted as code, which
would lead to compiler errors
The most basic element for XML documentation is < summary > , and it provides a short description of a
type or member Before moving on to anything more complicated, you should take a look at the
following example, which illustrates this element and how the results become visible
Try It Out Adding and Viewing Basic XML Documentation
1 Create a new console application called FirstXMLDocumentation and save it in the directory
C:\BegVCSharp\Chapter31
2 Add a class called DocumentedClass
Trang 83 Open the code for DocumentedClass , make the class definition public, add a new line before the class declaration, and type /// (three forward slashes)
4 Note that the IDE auto - completion adds the following code, placing the cursor inside the
< summary > element:
namespace FirstXMLDocumentation{
Trang 97 Open the Object Browser widow and expand the entry for the FirstXMLDocumentation
project until you can click DocumentedClass Note the summary information displayed in
the bottom - right pane, as shown in Figure 31 - 2
Figure 31-2
How It Works
This example demonstrates the basic technique for adding XML documentation and how this
documentation is used in the IDE When adding the basic summary information for your
DocumentedClass class, you saw how the IDE dynamically detects what you have in mind and fills
out the basic code for you IntelliSense and the Object Browser detect the documentation you added
without even having to compile the project These basic techniques apply to all aspects of XML
documentation and make it easy to add and consume this information
XML Documentation Comments
You can in fact add any XML you like to the XML documentation of a target (by target we mean type or
member ) However, some recommended elements and attributes will help your documentation to meet
standard guidelines The recommended XML is enough for most situations, and following this standard
means that tools that consume XML documentation (including IntelliSense and the Object Browser) can
interpret your documentation effectively
Brief descriptions of the basic elements for XML documentation are shown in the following table You ’ ll
look at each of these in more depth in subsequent sections
Trang 10< item > Represents an item in a list Used as a child of < list > , and can have
< description > and < term > children
< list > Defines a list Can have < listheader > and < item > children
< listheader > Represents the header row of a tabular list Used as a child of < list > , and
can have < description > and < term > children
< seealso > References another target, usually used outside of other elements, or at the
end of, for example, < summary >
< summary > Holds summary information concerning the target
< term > Marks text as being an item definition Used as a child element of < item > or
Trang 11Text Formatting Elements
Many of the elements shown in the preceding table are intended for formatting the text within other
elements A < summary > element, for example, might contain a combination of other elements that
specify the text to display The text formatting elements are < > , < code > , < list > , and its associated
elements, < para > , < paramref > , and < see > < seealso > is a special case that you can also include in this
list, as it can be included in a body of text, although it usually occurs at the end
< para >
The < para > element is used to separate text into paragraphs:
/// < summary >
/// < para > 1st paragraph of summary < /para >
/// < para > 2nd paragraph of summary < /para >
/// < /summary >
< c > and < code >
The < > and < code > elements are both used to format text in a code font, typically a monospaced font
such as Courier The difference is that < > can be thought of as “ code in text, ” that is, code words that
appear in the middle of sentences, whereas < code > is used for sections of code outside of text < > and
< code > might be used as follows:
< see > , < seealso > , < paramref > , and < typeparamref >
These four elements are all used to refer to other entries in the XML documentation for a project or to
external MSDN entries Commonly, each of these will be rendered as a hyperlink, enabling
documentation browsers to jump to other entries
< see > and < seealso > specify their target via a cref attribute, where the target can be any type or
member of any class, in the project or elsewhere < paramref > and < typeparamref > use a name
attribute to reference a parameter of the current target:
/// < summary >
/// < para >
/// This method uses < paramref name=”museName” / > to choose a muse
/// For more details, see < see cref=”MyPoet” / >
/// < /para >
/// < seealso cref=”MyParchment” / >
/// < seealso cref=”MyTheme” / >
/// < /summary >
Trang 12Note that the elements don ’ t include the text to display, which will typically be constructed from the
name , cref , or langword attribute You should bear this in mind to avoid repetition of text, for example:
/// This method uses < paramref name=”museName” / > museName to choose a muse
Here the word museName is likely to be repeated
< list > and Associated Elements
The < list > element is the most complicated text formatting element because it can be used in different ways It has an attribute called type that can be any of the following:
bullet — Formats a bulleted list number — Formats a numbered list table — Formats a table
A < list > element typically has a single < listheader > element child and several < item > children
Each of these may have < term > and < description > children The exact choice of which children to use will depend on the type of the list and the way your chosen tool formats lists < term > , for example, is optional in table format lists, while < listheader > might make sense only in a table For bulleted lists you could use something like the following:
/// < term > Muse name < /term >
/// < description > Muse’s favorite pizza < /description >
/// < /listheader >
/// < item >
/// < term > Calliope < /term >
/// < description > Ham & amp; Mushroom < /description >
/// < /item >
/// < item >
/// < term > Clio < /term >
/// < description > Four Seasons < /description >
/// < /item >
❑
❑
❑
Trang 13/// < item >
/// < term > Erato < /term >
/// < description > Meat Feast < /description >
/// < /item >
/// < /list >
/// < /para >
/// < /summary >
Because the exact behavior of the formatting with these elements may vary, it ’ s best to experiment a bit
Note that whatever you do with these elements, you won ’ t see any difference in the Object Browser,
which ignores them
Major Structural Elements
Several of the elements in the previous table are intended for use as top - level elements in the description
of a given target < summary > is a good example of this, as you saw in the earlier example The < summary >
element should never be contained in another element, and it is always used to provide summary
information about the target The other elements that fit this description are < example > , < exception > ,
< param > , < permission > , < remarks > , < returns > , and < value > < seealso > is a special case that
can be either a top - level element or a child of another element < include > is another special case,
because it effectively overrides other elements by fetching XML from an external file
You ’ ll look at each of these elements in turn
< summary > , < example > , and < remarks >
Each of these three elements provides general information about the target You ’ ve already seen
< summary > , which you can use to provide basic information about a target Because this information
appears in tooltips, it ’ s a good idea to keep this information short; put additional information in
< example > and < remarks >
Often when you are introducing a class, it can be helpful to give an example of how that class should be
used The same applies to methods, properties, and so on Rather than include this information in
< summary > , it can make sense to separate it into a new section, < example > :
Trang 14Similarly, < remarks > is often used to provide a longer description of a target, and it may include more
< see > and < seealso > elements for cross - referencing
< param > and < typeparam >
These elements describe a parameter, either a standard method parameter or a type parameter, for generic targets The parameter being referenced is set by using a name attribute These elements may occur several times if several parameters are used, as shown here:
< returns > and < value >
These two elements are similar in that they both refer to a return value: < returns > is used for the return value for methods, and < value > is used for the value of a property, which can also be thought of as a return value Neither of these elements uses any attributes
For methods, you might use < returns > as follows:
Trang 15< permission >
This element is used to describe the permissions associated with a target Actually setting the
permissions is performed by other means, such as applying a PermissionSetAttribute attribute to a
method; the < permission > element merely enables you to inform others about these permissions
The < permission > element includes a cref attribute, so you can, if you wish, reference a class that
includes additional information, such as System.Security.PermissionSet Here is an example:
/// < permission cref=”System.Security.PermissionSet” >
/// Only administrators can use this method
/// < /permission >
< exception >
This element is used to describe any exceptions that might be thrown during the use of the target It has
a cref attribute that you can use to cross - reference an exception type You might, for example, use this
element to state the range of allowed values for a property, and what would happen if someone
attempted to set the property to a value that isn ’ t allowed:
As previously mentioned, you can use the < seealso > element as a top - level element You can use
several of these, which, depending on the tool you use, may be formatted as a list of references at the end
of an entry for a target:
Including a lot of XML documentation in your source files can get a little messy, and you might want to
consider placing it in completely separate files This can also be desirable, for example, if someone else is
providing the documentation for your code, as you don ’ t have to give that person access to the source
files themselves
The < include > element enables you to do this, via its two attributes, file and path file specifies the
external XML file that contains the XML documentation you want to include, and path is used to locate
the specific section of XML within the document by using XPath syntax
Trang 16For example, you could reference some external XML as follows:
/// < include file=”ExternalDoc.xml” path=”documentation/classes/MyClass/*” / > public class MyClass
Here a file called ExternalDoc.xml is referenced This may contain code such as the following:
public class MyClass
Adding XML Documentation Using a Class Diagram
In Chapter 9 , you were introduced to class diagrams, and since then you ’ ve seen how you can use class diagrams to create classes diagrammatically, with changes reflected in your code in real time You ’ ve also learned how to add classes and members, modify the signatures of methods, and so on It should, therefore, come as no surprise that you can use class diagrams to add XML documentation to your classes, without getting bogged down in source code
Recall that class diagrams are available only in VS, and are not included in VCE You need VS in order
to work through this example
Unfortunately, as you will see, adding XML documentation in this way isn ’ t as flexible as adding it manually, but you do get the advantage of being able to do things very quickly, without having to remember any XML syntax
You ’ ll see the capabilities in the following Try It Out
Trang 17Try It Out Adding XML Documentation in a Class Diagram
1 Create a new class library application called DiagrammaticDocumentation and save it in the
directory C:\BegVCSharp\Chapter31
2 When the project has loaded, click the View Class Diagram button in the Solution Explorer
window You should see a diagram containing just the Class1 class that is generated for
you when you create a class library application
3 Add a class called DocumentedClass and modify its members as shown in Figure 31 - 3 and
the following table
Figure 31-3
Member Type Name Type Modifier Summary
Method GetFactors long[] public Gets the factors of a number
Property IncludeOne bool public Include 1 in GetFactors()
result Property IncludeSelf bool public Include self in GetFactors()
result
Trang 184 Click in the Summary box for the GetFactors() method, and then click the (ellipses) button Modify the text in the Description dialog as shown in Figure 31 - 4 and the following table
Figure 31-4
Field Value
Summary Gets the factors of a number Returns Returns a long array Remarks This method is used to obtain the factors of a number — that is, all the numbers that
the number can be divided by without leaving a remainder
If IncludeOne and IncludeSelf are both true and the result returned consists of exactly two numbers (the number itself and one), then the number is prime
5 Similarly, modify the Value and Remarks text for the IncludeOne and IncludeSelf properties, as shown in the following table:
Property Value Text Remarks Text
IncludeOne A bool value If this property is set to true , then GetFactors() will
include 1 in its long[] result
IncludeSelf A bool value If this property is set to true , then GetFactors() will
include its numberToFactor parameter in its long[] result
Trang 196 Click the class in the class diagram, and in the properties for the class, modify the Summary
and Remarks for the class as shown in the next table:
This class enables you to factorize a number
according to certain rules
Use GetFactor() to factorize a number according
to the rules defined by the IncludeOne and
IncludeSelf properties
7 Examine the code for DocumentedClass You should see the XML comments you have added
in place, such as the following:
/// < summary >
/// Gets the factors of a number
/// < /summary >
/// < remarks > This method is used to obtain the factors of a number, that is, all
/// the numbers that the number can be divided by without leaving a
/// < param name=”numberToFactor” > The number to factor < /param >
/// < returns > Returns a long array < /returns >
public long[] GetFactors(long numberToFactor)
{
throw new System.NotImplementedException();
}
How It Works
This example demonstrates how you can use a class diagram to set the XML documentation for a
project After reading the preceding section, you may be wondering why you haven ’ t included cross
references between methods and the like For example, why wasn ’ t the Remarks text for
GetFactors() set as follows:
This method is used to obtain the factors of a number, that is, all the
numbers that the number can be divided by without leaving a remainder
If < see cref=”IncludeOne” / > and < see cref=”IncludeSelf” / > are both < see
langword=”true” / > and the result returned consists of exactly two numbers
(the number itself and one) then the number is prime
The reason is because the text editor in the class diagram automatically escapes text that is entered
into the Description dialog, so the result of entering the previous code is actually the following:
/// < summary >
/// Gets the factors of a number
/// < /summary >
/// < remarks > This method is used to obtain the factors of a number, that is, all
/// the numbers that the number can be divided by without leaving a remainder
Trang 20/// If & lt;see cref=”IncludeOne” / & gt; and & lt;see cref=”IncludeSelf” / & gt; are/// both & lt;see langword=”true” / & gt; and the result returned consists of exactly/// two numbers (the number itself and one) then the number is prime < /remarks > /// < param name=”numberToFactor” > The number to factor < /param >
/// < returns > Returns a long array < /returns >
public long[] GetFactors(long numberToFactor){
throw new System.NotImplementedException();
}
This is unfortunately one of the inconveniences you have to cope with if you add XML documentation
by using a class diagram It ’ s great for adding text, but to embed XML documentation markup, you have to modify the code manually
Generating XML Documentation Files
So far, all the XML documentation you have added has been confined to the development environment while you are working with a project If you want to actually do anything with the documentation you add, you have to set the project to output the documentation as an XML file
To do this, you need to modify the build settings for your project, as shown in Figure 31 - 5
Trang 21The only changes to make are to check the XML Documentation File box and supply an output filename
It is generally a good idea to save the XML documentation file in the same directory as the assembly
because that is where the IDE searches for it If you have a client application to a documented assembly
in a different solution, you get the benefits of IntelliSense and help in the Object Browser only if the IDE
can find the XML documentation file
Once the build setting for XML documentation is turned on, the compiler will be configured to actively
search for XML documentation in your classes While it isn ’ t necessarily an error to omit XML
documentation for a given class or method, the IDE will alert you to anything missing, in the form of
warnings in the Error List window An example is shown in Figure 31 - 6
Figure 31-6
This warning, obtained from the previous example, indicates that documentation is missing for the
Class1 class (which you left unchanged)
Here ’ s the XML documentation file created for the previous example:
< remarks > Use GetFactor() to factorize a number according to the rules
defined by the IncludeOne and IncludeSelf properties < /remarks >
This method is used to obtain the factors of a number, that is, all the
numbers that the number can be divided by without leaving a remainder
If IncludeOne and IncludeSelf are both true and the result returned
consists of exactly two numbers (the number itself and one) then the
number is prime
< /remarks >
< returns > Returns a long array < /returns >
< /member >
Trang 22< member name=”P:DiagrammaticDocumentation.DocumentedClass.IncludeOne” >
< summary >
Include 1 in GetFactors() result
< /summary >
< remarks > If this property is set to true, then GetFactors() will include
1 in its long[] result < /remarks >
< value > A bool value < /value >
This document contains the following:
A root level < doc > element containing all other documentation information
An < assembly > element containing a < name > element containing the name of the assembly to which the XML documentation applies
A < members > element containing the XML documentation for each member in the assembly Several < member > elements, each with a name attribute stating to which type or member the XML documentation contained by the < member > element applies
The name attributes of the < member > elements follow a consistent naming scheme They are all names belonging to one of the following namespaces — that is, they all start with one of the following letters:
T — Specifies that the member is a type (class, interface, strut, enumeration, or delegate)
M — Specifies that the member is a method
P — Specifies that the member is a property or indexer
F — Specifies that the type is a field or enumeration member (not shown in the example)
E — Specifies that the member is an event (not shown in the example) Any errors in the XML documentation for a type are shown in the generated file as a commented
< member > element:
< ! Badly formed XML comment ignored for member “T:DiagrammaticDocumentation.DocumentedClass” >
Within a < member > element, the XML documentation for a target is inserted exactly as is (unless there is
a problem with the XML)
Trang 23Example Application with XML Documentation
For the remainder of this chapter, you ’ ll look at ways to use XML documentation files; and to make this
easier, you ’ ll be using a fully functional example class library called DocumentedClasses, which comes
packed with XML documentation of almost all types
The classes in the DocumentedClasses library are shown in Figure 31 - 7
Figure 31-7
The idea behind this class library is that a client application can create an instance of a Garden class and
then add instances of classes derived from GardenContent to the garden This can then be used to
obtain a simple graphical representation of the garden The classes effectively form a very basic garden
design tool
The downloadable code for this chapter includes this class library, should you want to investigate the
code for yourself, but there is no real need to present it all here Also included in the downloadable code
is a simple client application called DocumentedClassesClient, with code as follows:
static void Main(string[] args)
Trang 24for (int y = 0; y < gardenDepth; y++) {
for (int x = 0; x < gardenWidth; x++) {
Console.Write(plan[x, y]);
} Console.WriteLine();
} Console.ReadKey();
}
This illustrates how to use the classes in DocumentedClasses, and results in the output shown in Figure 31 - 8
Figure 31-8
Trang 25As you can see, very basic indeed! (Luckily, if you are a garden designer, there are better tools available.)
Of course, here you are merely interested in the XML documentation contained in DocumentedClasses
Making Use of XML Documentation
This chapter has mentioned in several places that there is much more that you can do with XML
documentation than simply use it to supply IntelliSense information to the IDE — which isn ’ t to say that
customized IntelliSense isn ’ t an extremely useful feature
Perhaps the simplest thing you can do with XML documentation is ship it with your assemblies and
leave it up to other people to make use of it, but this is far from ideal In this section, you look at some of
the possibilities for getting the most out of your documentation
Programmatically Processing XML Documentation
The most obvious thing to do with XML documentation is to make use of the wealth of XML tools in the
.NET namespaces Using the techniques and classes you saw in Chapter 25 , it is possible to load XML
documentation into an XmlDocument object The following Try It Out is a simple console application that
does just that
This Try It Out requires the XML documentation output from the example project, DocumentedClasses
Before starting this Try It Out, download and build the DocumentedClasses solution
Try It Out Processing XML Documentation
1 Create a new console application called XMLDocViewer in the directory
3 Modify the code in Main() as follows:
static void Main(string[] args)
{
// Load XML documentation file
XmlDocument documentation = new XmlDocument();
Trang 26XmlNodeList memberNodes = documentation.SelectNodes(“//member”);
// Extract < member > elements for types
List < XmlNode > typeNodes = new List < XmlNode > ();
foreach (XmlNode node in memberNodes) {
if (node.Attributes[“name”].Value.StartsWith(“T”)) {
typeNodes.Add(node);
} } // Write types to the console
Console.WriteLine(“Types:”);
foreach (XmlNode node in typeNodes) {
Console.WriteLine(“- {0}”, node.Attributes[“name”].Value.Substring(2)); }
Console.ReadKey();
}
4 Execute the application The result is shown in Figure 31 - 9
Figure 31-9
How It Works
This example demonstrates the basics of loading and processing an XML documentation file in C#
code You start by loading in a documentation file, which in this case is the one generated by the DocumentedClasses type library:
XmlDocument documentation = new XmlDocument();
Trang 27When you have a list of < member > elements, you can search through them, looking for those that start
with a T to get the elements that refer to types, and placing them into a List < XmlNode > collection:
List < XmlNode > typeNodes = new List < XmlNode > ();
foreach (XmlNode node in memberNodes)
You could, of course, achieve this in a single step using a more advanced XPath expression that
included an attribute check, but why overcomplicate things? Finally, you output the names of the
types found to the console:
There ’ s a lot more that you could do here, as navigating and processing XML files in NET isn ’ t a
complicated process However, because there are better ways of handling XML documentation, as
you ’ ll see in the next two sections, there is no real need to take this example further
Styling XML Documentation with XSLT
Because XML documentation is, by definition, XML, there is plenty of scope for using XSLT
transformations to convert your XML into HTML, or even to use XSLT formatting objects to create
printable documentation
At this point, we ’ d like to defer to the true master of (and driving force behind) C# — Anders Hejlsberg
He has published an XSLT document and associated CSS file to turn XML documentation files into
stylish HTML These two files, doc.xsl and doc.css , can be found in the downloadable code for this
chapter in the directory XSLTStyledXMLDocumentation In order to use these files, simply add a
processing directive to your XML documentation files as follows:
Trang 28You ’ ll also find a version of DocumentedClasses.xml in the XSLTStyledXMLDocumentation directory that includes this directive A sample of the result is shown in Figure 31 - 10
Figure 31-10
The styling isn ’ t perfect — < seealso > elements in particular don ’ t come out right, and you can see
in the screenshot that there are problems with < code > formatting — but overall it ’ s pretty impressive The files make an excellent starting point should you wish to make a Web page of your documentation
The way that the < see > elements link to anchors on the page is particularly good
Perhaps the biggest problem with doing things this way is that everything appears in a single HTML page, which could get very large indeed
Documentation Tools
An alternative way of processing XML documentation is to use a tool Until recently, the tool of choice for XML documentation styling was NDoc NDoc is a third - party tool that is capable of converting your documentation into a number of formats, including MSDN - style help files Unfortunately, development
on NDoc is (at the time of writing) stalled
To obtain the most recent version of NDoc (which is free), head to http://ndoc.sourceforge.net Although it hasn ’ t been upgraded for some time, it ’ s still functional (as long as you use the NET
Trang 29Framework 1.x version) It is possible that the project may become live again at some point in the future,
so it ’ s worth a look Figure 31 - 11 shows an example of NDoc documentation in a help - style format
Figure 31-11
With the possible demise of NDoc, it is worth looking at Sandcastle, an alternative tool It ’ s the tool that
Microsoft uses to generate API documentation, so it is as fully featured as you would expect it to be It
has full support for the latest NET Framework version and C# language features, including support for
example generics that NDoc does not support
However, as Sandcastle is effectively an internal tool, it is not the easiest thing to use Several GUIs exist
for the tool, most of which have been created by its users
You can find out more at www.sandcastledocs.com or http://blogs.msdn.com/sandcastle You
can also download a popular GUI for Sandcastle at www.codeplex.com/SHFB
Trang 30Summar y
In this chapter, you looked at all aspects of XML documentation, from how to create it to what you can
do with it Specifically, you have learned the following:
XML documentation syntax How to include external XML documentation How XML documentation is used in VS IntelliSense and the Object Browser How to use class diagrams to add XML documentation
How to generate XML documentation files How to process XML documentation files in C# How to style XML documentation with XSLT How to use tools such as NDoc and Sandcastle to compile help files from XML documentation Admittedly, adding XML documentation to your projects can be a time - consuming process, and it can make your source code look a bit messy; but in large - scale projects, it is an essential part of development, and the result is well worth the effort — especially when you use a tool designed for the purpose
2 Which top - level XML documentation tags would you use to document a property?
3 XML documentation is contained in C# source files True or false?
4 What is the major disadvantage of adding XML documentation using a class diagram?
5 What do you need to do to ensure that other projects can make use of XML documentation in your class libraries?
Trang 3232
Networ king
Chapter 21 dealt with a high - level technology to communicate across the network: Web Services
You learned how to send messages from the client to the server in a platform - independent way with the SOAP and NET - specific protocols In this chapter, you step into lower networking layers, programming with classes from the namespace System.Net Web Services itself uses this
TcpListener and TcpClient Socket programming
Networ king Over view
Networking is about communicating with applications on other systems The communication happens by sending messages Messages can be sent to a single system where a connection is initiated before the message, as shown in Figure 32 - 1 , or messages can be sent to multiple systems
by a broadcast , as shown in Figure 32 - 2 With a broadcast, connections are not initiated; the
messages are just sent to the network instead
Trang 33Sender
Connection
Figure 32-1
Networking can be best illustrated by showing the seven OSI layers Figure 32 - 3 shows the stack of the
OSI layers with their corresponding TCP/IP layers Often the layers are also defined by numbers that are
simply increments of the layers — from the bottom, where the physical layer is number 1, to the top,
where the application layer is number 7
ReceiverReceiver
Receiver
Receiver
Sender
Figure 32-2
Trang 34TCP UDP
PresentationSessionTranspor tNetworkData Link
Internet Protocol
EthernetPhysical
Figure 32-3
The lowest OSI layer is the physical layer At the physical layer, physical devices (such as networking cards and cables) are defined The data link layer accesses the physical network with physical addresses The data link layer performs error correction, flow control, and hardware addressing The address of your Ethernet network card shows up when you use the ipconfig /all command The system shown here has the MAC address 00 - 13 - 02 - 38 - 0D - 5C:
C:\ > ipconfig /all Windows IP Configuration
Host Name : farabove Primary Dns Suffix : explorer.local Node Type : Hybrid
IP Routing Enabled : No WINS Proxy Enabled : No DNS Suffix Search List : explorer.local kabsi.at
Wireless LAN adapter Wireless Network Connection:
Connection-specific DNS Suffix : kabsi.at Description : Intel(R) PRO/Wireless 3945ABG Network Connection
Physical address : 00-13-02-38-0D-5C DHCP Enabled : Yes
Autoconfiguration Enabled : Yes Link-local IPv6 Address : fe80:bd:3d27:4106:9f4c%10(Preferred) IPv4 Address : 192.168.0.31(Preferred)
Subnet Mask : 255.255.255.0 Lease Obtained : Sunday, July 29, 2007, 3:10:08 PM Lease Expires : Wednesday, August 01, 2007, 3:10:08 PM Default Gateway : 192.168.0.6
DHCP Server : 192.168.0.6 DHCPv6 IAID : 167777026 DNS Servers : 192.168.0.10 195.202.128.2 NetBIOS over Tcpip : Enabled
Trang 35The network layer uses a logical address to address systems in a WAN The Internet Protocol (IP) is a
layer 3 protocol; at layer 3, an IP address is used to address other systems In IPv4, the IP address
consists of 4 bytes — for example, 192.14.5.12
The transport layer is used to identify the applications that communicate The applications can be
identified by endpoints The server application waiting for clients to connect has a known endpoint to
connect to Both the Transmission Control Protocol (TCP) and User Datagram Protocol (UDP) are layer 4
protocols that use a port number (the endpoint) to identify an application The TCP protocol is used for
reliable communication in which a connection is set up before data is sent; whereas with the UDP
protocol, communication is unreliable because data is sent without a guarantee that it will be received
Above layer 4, the OSI layers define a session, presentation, and application layer The session layer
defines services for an application, such as logging in to and out of an application The session
layer enables a virtual connection between applications You can compare this with ASP.NET sessions,
discussed in Chapter 18 The presentation layer is about data formatting — it is within this layer that
encryption, decryption, and compression can happen Finally, the application layer is the highest layer to
offer networking features to applications, such as file transfers, e - mail, Web browsing, and so on
With the TCP/IP protocol suite, the application - level protocols cover layers 4 to 7 of the OSI layer model
A few examples of these protocols are Hypertext Transfer Protocol (HTTP), File Transfer Protocol (FTP),
and Simple Mail Transfer Protocol (SMTP) At the transport layer, endpoints are used to reach other
applications; these application protocols define how the data that is sent to the other system looks Later
you will see what data is sent with HTTP
Name Resolution
The Internet Protocol requires IP addresses Because the IP addresses aren ’ t easy to remember (and are
even more difficult with IPv6, where the IP address consists of 128 bits instead of 32 bits), a hostname is
used For communication between the systems, however, the IP address is required, as discussed earlier
To map the hostname to the IP address, Domain Name System (DNS) servers are used
Windows has a command - line tool, nslookup, that can do name lookups (resolve IP addresses from
hostnames) or reverse lookups (resolve hostnames from IP addresses) Reverse lookups are interesting
because by analyzing the log files where the IP address of client systems can be found, you can
determine the origin of the client system
With NET, you can perform name lookups with the Dns class in the System.Net namespace With the
Dns class, a hostname can be resolved to its IP addresses, or an IP address can be resolved to its
hostname Let ’ s try it out with a simple project
Try It Out Using DNS
1 Create a new C# console application project named DnsLookup in the directory
C:\BegVCSharp\Chapter32
2 Import the namespace System.Net
Trang 363 Invoke the GetHostEntry() method of the Dns class, as shown here, after checking the arguments from the Main() method:
static void Main(string[] args) {
if (args.Length != 1) {
Console.WriteLine(“Usage: DnsLookup hostname/IP Adddress”);
return;
} IPHostEntry ipHostEntry = Dns.GetHostEntry(args[0]);
4 Add the following code to the Main() method that follows the call to the
GetHostEntry() method to write information about the resolved host to the console:
Console.WriteLine(“Host: {0}”, ipHostEntry.HostName);
if (ipHostEntry.Aliases.Length > 0) {
foreach (IPAddress address in ipHostEntry.AddressList) {
Console.WriteLine(“Address: {0}”, address.ToString());
} }
5 Compile the application and start the program Pass a hostname as a command - line argument —
for example, www.microsoft.com To start it from Visual Studio, you can set the command - line arguments with the Debug configuration, as shown in Figure 32 - 4 You can also start a command prompt, change to the directory of the executable, and start the application with
dnslookup www.microsoft.com You should get output that looks similar to the following:
Host: lb1.www.ms.akadns.net
Address(es):
Address: 207.46.193.254Address: 207.46.19.190Address: 207.46.19.254Address: 207.46.192.254
Trang 37How It Works
The Dns class queries the DNS server to resolve hostnames to IP addresses and to do reverse lookups
to get a hostname from an IP address To do this, the Dns class uses the GetHostEntry() method, with
which you can pass a hostname, and an IPHostEntry will be returned For reverse lookups, the
GetHostByAddress() method can be called
In all cases, the Dns class returns an IPHostEntry This class wraps information about a host The
IPHostEntry class has three properties: HostName returns the name of the host, Aliases returns a list
of all alias names, and AddressList returns an array of IPAddress elements The ToString() method of
the IPAddress class returns the Internet address in a standard notation
Uniform Resource Identifier
The resources that can be accessed across the network are described by a URI (Uniform Resource
Identifier) You use URIs every day when you enter Web addresses, such as http://www
.thinktecture.com , in your Web browser The class Uri encapsulates a URI and has properties and
methods for parsing, comparing, and combining URIs
A Uri object can be created by passing a URI string to the constructor:
Uri uri = new Uri(“http://www.wrox.com/go/p2p”);
If you go to different pages on the same site, you can use a base URI and construct out of it URIs that
contain the directories:
Uri baseUri = new Uri(“http://msdn.microsoft.com”);
Uri uri = new Uri(baseUri, “downloads”);
Figure 32-4
Trang 38You can access parts of the URI by using properties of the Uri class The following table shows a few examples of what you can get out of an Uri object that is initialized with the URI http://www.wrox.com/marketbasket.cgi?isbn=0470124725
Uri Property Result
Scheme http
Host www.wrox.com
Port 80
LocalPath /marketbasket.cgi
The UDP protocol is similar in that the server must create a socket with a well - known port number, and the client uses a freely available port number The difference is that the client doesn ’ t initiate a connection Instead, the client can send the data without making a connection first Without a connection, there ’ s no guarantee that the data is received at all, but the overall transfer is faster The UDP protocol has the big advantage that broadcasts can be done with it — sending information to all systems in the LAN by using a broadcast address
Broadcast addresses are IP addresses for which all bits of the host part of the IP address are set to 1
Application Protocols
This section looks at application protocols that make use of TCP or UDP HTTP is an application protocol that is layered on top of TCP The HTTP protocol defines the message that is sent across the network
Trang 39Using the HTTP protocol to request data from a Web server, a TCP connection is opened, and then an
HTTP request is sent An example of an HTTP request initiated by a browser looks like this:
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; NET CLR
2.0.50727; Media Center PC 5.0; Tablet PC 2.0; NET CLR 1.1.4322; NET CLR
3.5.20706; NET CLR 3.0.590)
Host: localhost:80
Connection: Keep-Alive
This sample request shows a GET command Some of the most frequently used HTTP commands are
GET , POST and HEAD GET is used to request a file from the server With the POST command, a file is
requested from the server, too, but unlike with the GET command, with the POST command additional
data is sent after the HTTP header With the HEAD command, the server returns only the file ’ s
header information, so that the client can determine whether the file is different from data already in
the cache
The GET command requests the file on the server Here, the server should return the file /default
.aspx The last section of the first line defines the HTTP version If both the client and server support
version 1.1, then this version is used for the communication Otherwise, HTTP 1.0 is used With HTTP
1.1 it is possible to keep the same connection (see the HTTP header information Connection:
Keep - Alive )
After the first line of the request with the GET command, HTTP header information follows The browser
sends information about itself with the request In the example, you can see the Accept information,
where mime types of supported programs are sent The Accept - Language header defines the languages
that are configured on the browser The server can use this information to return different information to
the client, depending on the supported files and languages With the User - Agent header, the browser
sends information about the client application used to request the page from the server Here, Internet
Explorer 7.0 is used with Windows Vista Windows Vista has the identifier Windows NT 6.0 The server
can also read whether the NET runtime is installed on the client system Here, NET 1.1, NET 2.0, NET
3.0, and NET 3.5 appear as supported NET versions
After the server receives a GET request, a response message is returned An example of a response
message is shown in the following example If the request succeeds, then the first line of the response
shows an OK status and the HTTP version used Then HTTP header information follows, which includes
the Server , the Date , and the Content - Type and the length that follows the header The header and the
content are separated by two lines:
HTTP/1.1 200 OK
Server: Microsoft-IIS/7.0
Date: Sun, 29 Jul 2007 20:14:59 GMT
X-Powered-By: ASP.NET
Trang 40X-AspNet-Version: 2.0.50727Cache-Control: privateContent-Type: text/html; charset=utf-8Content-Length: 991
< !DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN” >
< HTML >
HEAD >
< title > Demo < /title >
You can easily simulate an HTTP request by using the telnet utility, which you do with the next Try It Out
Try It Out Simulate an HTTP Request
1 Start the telnet client by typing telnet.exe at a command prompt The prompt Microsoft Telnet > appears With Windows Vista, the telnet client is not installed by default If it is missing on your system, then select Control Panel Programs Turn Windows Features On
or Off; and select the check box for the Telnet Client to install it
2 To see the commands you type and send to the server, enter set localecho in the telnet session
3 Create a connection to the Web server in your LAN If you have a Web server on the local
system, enter open localhost 80 80 is the default port number used with the Web server
4 Send a request to the Web server by typing the command GET / HTTP/1.1 , and then press
Return twice With the / , the default page from the server is returned — for example,
default.htm Instead of using the / , you can request specific filenames Sending two newline characters marks the end of the transmission Now you get a response from the server that looks similar to the response shown earlier
Networ king Programming Options
The System.Net and System.Net.Sockets namespaces offer several options for networking programming Figure 32 - 5 shows those options The easiest way to do network programming is by using the WebClient class Just a single method of this class is needed to get files from a Web server or to transfer files to an FTP server However, the functionality of this class is limited With NET 3.5, you can use it only with the HTTP and the FTP protocols, and to access files Of course, you can also plug in custom classes to support other protocols