oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Using NDoc: Adding World-Class Documentation to Your .NET Components
Pages: 1, 2

Using the <include> Tag To Keep Docs Out of Sight, But Not Out of Mind

As I mentioned earlier, one of the traditional problems with source-code-based documentation generators is that in order to write full-fledged documentation for your product, you must swamp your code in comments. (Too many comments? Yes indeed, it is always possible to have too much of a good thing.)

The doc-comment feature of the C# compiler addresses this problem nicely by allowing you to keep the meat of your documentation in a separate XML file. You need only insert one line of doc-comment code, the <include> element, to link that part of your source code to the appropriate bits in your XML doc.

Use of the <include> element requires you to specify two attributes: the relative path to the XML file, and an XPath expression to point to the XML node(s) to include. If you're new to XPath, this is a perfect opportunity to learn this important bit of XML technology -- see the References section for links to some XPath tutorials.

/// <include file='myrefdocs.xml' 
///     path='//Class[@name="Foo"]/summary'
/// />
/// <include file='myrefdocs.xml' 
///     path='//Class[@name="Foo"]/remarks'
/// />
/// <include file='myrefdocs.xml' 
///     path='//Class[@name="Foo"]/seealso'
/// />
public class Foo
{ ... }

The XPath expressions in the above example grab the <summary>, <remarks>, and <seealso> child elements from all <Class> elements with the name="Foo" attribute. I just made this up -- you're free to invent your own XML grammar to organize your documentation.

<?xml version="1.0"?>
  <Namespace name="Arithex.Samples">
    <Class name="Foo">
      <summary>This is a sample class.</summary>
        Here are some interesting remarks about the Foo sample class.
      <seealso cref="Bar" />

For serious software engineering projects, it's well worth your time to make use of the <include> element in this way. You can split the documentation up among multiple XML files, in any way you wish -- you'll be able to hand off these XML doc files to a team of tech writers, or even other engineers, who'll be able to check the files in and out of source code control independent of the actual C# source code, thus avoiding many merging-related headaches for you or your team. For example, in a project I'm currently working on, we've decided to split the XML documentation into separate peer files for each C# file -- where Foo.cs would be accompanied by a Foo.xml file, which contains the meat of the documentation. For smaller projects, keeping all of the docs in single XML file may serve you better. You can even choose to mix and match (perhaps keeping the <summary> elements inline in your C# code, and everything else out-of-line in a separate XML file).

NDoc Extensions to C#'s XML Documentation Tags

There are a few important bits missing from Microsoft's specification of C#'s XML Documentation feature. The most notable of these is a way to specify a common summary for the overloads of a function. This is where NDoc really comes into its own: because the format of the docs output by the C# compiler is XML, it's trivial for NDoc to extend the schema to include any missing bits. The C# compiler doesn't complain -- it will pass through any XML tags it doesn't recognize into the resulting documentation, where they can be interpreted by third-party tools (like NDoc).

NDoc extends the set of Microsoft-defined tags by defining a new <overloads> tag, a new <events> tag for documenting the events raised by a member function, and extending the grammar of the <see> and <seealso> tags to allow linking to arbitrary URLs (not just other code items).

You can find some rudimentary documentation for these extended tags in the tags.html file, which is included in the NDoc distribution. The <overloads> tag requires a bit of explanation -- it comes in two flavors: simple and complex.

The simple form of <overloads> is used very much like a <summary> tag, to provide a short description string for the suite of overloaded methods. (If you neglect to provide an <overloads> tag, NDoc will use the <summary> tag on the first overload to describe the overloaded method.)

Figure 1: NDoc-generated text for an overloaded method

NDoc-generated text for an overloaded method

The more complex form of <overloads> allows you to specify other common documentation items, such as a <remarks> section. Unfortunately, it's not a general-purpose dumping ground for all documentation items that are relevant to the individual overloaded methods -- you can't, for example, place documentation for the overloads' common parameters in the <overloads> element and expect them to show up. However, with a little creative application of the <include> tag, you can easily achieve this effect. The sample project accompanying this article demonstrates the combined use the <overloads> and <include> tags, for an overloaded method named Solve:

<Method name="Solve">
    <overloads>Attempts to solve the function.</overloads>
    <param name="guessX1">An initial guess.</param>
    <param name="guessX2">Another initial guess.</param>
    <param name="resultPrecision">
      Desired precision for solution.
    <param name="resultStatus">
      The outcome of the solution.
      The root of the equation (or Double.NaN, upon error).

<Method name="Solve1">
    <summary>Attempts to solve the function, using the default 
      max. number of iterations.</summary>
    <remarks>Attempts to solve the function, using the default 
      max. number of iterations.</remarks>

<Method name="Solve2">
    <summary>Attempts to solve the function, using the specified 
      max. number of iterations.</summary>
    <remarks>Attempts to solve the function, using the specified 
      max. number of iterations.</remarks>
    <param name="maxIterations">
      Maximum number of iterations to search.

Linking to External Documentation

One of the nicer features of NDoc is the way it provides seamless links to documentation in the .NET Framework SDK -- it even goes so far as to extract XML documentation for members inherited from their respective assemblies' XML doc-comment files -- but it can only provide links for the types it knows about.

For other types -- types defined in third-party assemblies -- you're on your own. That's not to say the situation is impossible, just that you have to do a little work.

Let's say you have a method with a parameter of type AcmeSoft.Foo, defined in AcmeSoft.dll. You know that AcmeSoft has wonderful documentation for their product, available online at, but there's a problem: NDoc will generate a hyperlink from your method's page to a non-existent help topic "AcmeSoft.Foo.html". If you try to follow this link in the HtmlHelp browser, you'll be greeted with an error message. That page doesn't exist in your CHM file, because that type doesn't exist anywhere in your assembly, so NDoc didn't generate it. To rectify the situation, all you need to do is supply the missing ingredient: author an HTML page (manually), name it "AcmeSoft.Foo.html," and pre-place it into the NDoc output directory before running NDoc (or at least before running the HtmlHelp compiler).

It's a bit of a hack -- relying on an accident of NDoc's implementation, perhaps -- but it works, until a future version of NDoc offers a better alternative. And by writing your own page, you're allowed the flexibility you need to warn the user that they're about to start reading third-party documentation, and/or that you're about to connect to them to the Internet, etc.


With each new project I work on, I grow continuously more impressed with the flexibility and versatility of NDoc. It's saved me hundreds of hours of tedious labor engineering my own MSDN-style documentation solution, and it looks good doing it!

For a jumpstart into the wonderful world of NDoc, download the sample project accompanying this article, and see if you don't fall in love yourself.


Shawn Van Ness is an independent consultant specializing in the development of secure, efficient, and robust distributed software systems, based on .NET, COM, and XML technologies.

Return to