Hands-On Labs Sandcastle

05 December 2010 - .NET

This week I will be one of the speakers at BASTA On Tour in Munich. One of the topics I am going to speak about is code documentation with Sandcastle. In this blog post I want to share my slides and summarize the hands-on labs that I am going to go through with the participants.

Hands-On Lab 1: The Raw Sandcastle Process

Although it is likely that you will use one of the sandcastle UI tools that the community provides it is worthful to have an understanding about what happens behind the scenes. Therefore you will use the raw sandcastle command-line api to generate a CHM file for a sime C# sour file in this first hands-on lab.

Prerequisites:

  1. Download and install the June 2010 release of Sandcastle from http://sandcastle.codeplex.com/
  2. Option: Install the latest Sandcastle style path from http://sandcastlestyles.codeplex.com/

Lab step by step description:

  1. Copy sandcastle's Examples folder:
    copy c:\Program Files (x86)\Sandcastle\Examples c:\temp\Sandcastle Examples
  2. Open a Visual Studio Command Prompt (2010)
  3. switch to the folder that you have copied the sandcastle examples to:
    cd c:\temp\Sandcastle Examples
  4. Take a look at test.cs. This is the sample C# file that we are going to generate a documentation for.
  5. Compile test.cs and generate XML documentation for the file:
    csc /t:library /doc:comments.xml
  6. The a look at comments.xml. The C# compiler has generated this file from the C# source file test.cs because you specified the option /doc when calling csc.
  7. Because of the complexity of the Sandcastle help generation process Sandcastle comes with a sample script that includes all necessary steps to generate the CHM file. The sample script is called build_Sandcastle.bat. Open the file in a text editor and note how MRefBuilder, BuildAssembler and the XSL transformations are used.
  8. Build the documentation for test.cs using the sample script mentioned in the previous step:
    build_Sandcastle.bat vs2005 test chm
  9. Open the following files in a text editor and take a look at them. They have been generated by the Sandcastle process.
    1. reflection.xml
    2. manifest.xml
    3. toc.xml
  10. Note how Sandcastle generated the necessary source file for CHM generation:
    1. chm\test.hhc
    2. chm\test.hhk
    3. chm\test.hhp
    4. Content in chm\html, chm\icons, chm\scripts and chm\styles
  11. Open the resulting CHM file chm\test.chm.

Hands-On Lab 2: Sandcastle Helpfile Builder

Prerequisites:

  1. Download and install the July 2010 release of Sandcastle Help File Builder (SHFB) from http://shfb.codeplex.com/
  2. Execute Hands-on lab 1 (see above) so that you have a compiled version of the file test.cs.

Lab step by step description:

  1. Launch Sandcastle Help File Builder.
  2. Create a new project called test.shfbproj.
  3. Add test.dll and comments.xml (both results from lab 1) as a documentation source using the SHFB's project explorer.
  4. Build project using Documentation / Build Project.
  5. Launch generated CHM file using Documentation / View Help File / View HTML Help 1 (.chm) File
  6. Experiment with different project settings; try to generate and launch MSHelpViewer help file format using the project's HelpFileFormat property.

Hands-On Lab 3: Documenting Sample Class Library

Prerequisites:

  1. Download and install the latest release of StyleCop from http://stylecop.codeplex.com/
  2. Download and install the latest release of GhostDoc from http://submain.com/products/ghostdoc.aspx

Lab step by step description:

  • Launch Visual Studio 2010
  • Create a new C# Class Library project called CSharpCodeDoc
  • Add the following class to the class library:
    namespace CSharpCodeDoc
    {
     using System;
     using System.Collections.Generic;
     using System.IO;
    
     public class SwiftFileReader<T> : TextReader
     {
      private static object lockObject;
    
      static SwiftFileReader()
      {
       lockObject = new object();
      }
    
      public SwiftFileReader()
       : this(TimeSpan.FromMinutes(1))
      {
      }
    
      public SwiftFileReader(TimeSpan timeout)
      {
       this.Timeout = timeout;
      }
    
      public TimeSpan Timeout { get; set; }
    
      public int Size { get; private set; }
    
      public bool HasReachedLimit { get; private set; }  public IEnumerable<TDest> ConvertFileContent<TDest>(int sizeLimit)
      {
       throw new NotImplementedException();
      }
    
      public override string ReadToEnd()
      {
       return base.ReadToEnd();
      }
     }
    }
  • Make sure that the class library builds correctly.
  • Right-click on the project in Solution Explorer and open choose StyleCop Settings.
  • Disable all Documentation Rules.
  • Run StyleCop on the project using Tools / Run StyleCop and make sure that there are no errors or warning.
  • Enable all Documentation Rules / Element Documentation rules (do not enable Documentation Rules / File Headers).
  • Run StyleCop on the project using Tools / Run StyleCop. Note that StyleCop shows warnings because of missing XML code documentation.
    • Tip: You could integrate this step in your corporate's build process and even treat StyleCop warnings as errors. With this you can make sure that developers do not forget to write code documentation XML.
  • Add documentation header to class:
    /// <summary>
    /// Represents a reader for SWIFT files
    /// </summary>
    /// <typeparam name="T">Parameter type that should be used for reading files</typeparam>
  •  Run StyleCop on the project using Tools / Run StyleCop. Note that StyleCop tells you that you have forgotten the period at the end of the summary text.
    • Correct that error by adding the period
  • Set the cursor in the name of the property HasReachedLimit.
  • Auto-generate documentation for the property using GhostDoc by pressing Ctrl + Shift + D or by selecting Tools / GhostDoc / Documentthis.
    • Note how GhostDoc derives documentation from the property's name and type.
  • Set the cursor in the name of the method ReadToEnd.
  • Auto-generate documentation for the method using GhostDoc by pressing Ctrl + Shift + D or by selecting Tools / GhostDoc / Document this.
    • Note how GhostDoc reads documentation from the base class.
  • Add and correct the code documentation so that the class file looks like this:
namespace CSharpCodeDoc
{
 using System;
 using System.Collections.Generic;
 using System.IO;

 /// <summary>
 /// Represents a reader for SWIFT files.
 /// </summary>
 /// <typeparam name="T">Parameter type that should be used for reading files.</typeparam>
 public class SwiftFileReader<T> : TextReader
 {
  /// <summary>
  /// Internal helper object used for locking.
  /// </summary>
  private static object lockObject;

  /// <summary>
  /// Initializes static members of the SwiftFileReader class.
  /// </summary>
  static SwiftFileReader()
  {
   lockObject = new object();
  }

  /// <summary>
  /// Initializes a new instance of the <see cref="SwiftFileReader{T}"/> class.
  /// </summary>
  public SwiftFileReader()
   : this(TimeSpan.FromMinutes(1))
  {
  }

  /// <summary>
  /// Initializes a new instance of the <see cref="SwiftFileReader{T}"/> class.
  /// </summary>
  /// <param name="timeout">Timeout for reading (see <see cref="Timeout"/>).</param>
  public SwiftFileReader(TimeSpan timeout)
  {
   this.Timeout = timeout;
  }

  /// <summary>
  /// Gets or sets the timeout for reading.
  /// </summary>
  /// <value>Timeout for reading.</value>
  public TimeSpan Timeout { get; set; }

  /// <summary>
  /// Gets the size of the file.
  /// </summary>
  /// <value>Size of the file.</value>
  public int Size { get; private set; }

  /// <summary>
  /// Gets a value indicating whether this instance has reached limit.
  /// </summary>
  /// <value>Returns <c>true</c> if this instance has reached limit; otherwise, <c>false</c>.
  /// </value>
  public bool HasReachedLimit { get; private set; }

  /// <summary>
  /// Converts the content of the file.
  /// </summary>
  /// <typeparam name="TDest">Type of resulting objects.</typeparam>
  /// <param name="sizeLimit">The size limit for the result.</param>
  /// <returns>
  /// <para>Returns the file's content as an enumerable.</para>
  /// <para>The result contains max. <paramref name="sizeLimit"/> objects.</para>
  /// </returns>
  public IEnumerable<TDest> ConvertFileContent<TDest>(int sizeLimit)
  {
   throw new NotImplementedException();
  }

  /// <summary>
  /// Reads all characters from the current position to the end of the TextReader and returns them as one string.
  /// </summary>
  /// <returns>
  /// A string containing all characters from the current position to the end of the TextReader.
  /// </returns>
  /// <exception cref="T:System.IO.IOException">An I/O error occurs. </exception>
  /// <exception cref="T:System.ObjectDisposedException">The <see cref="T:System.IO.TextReader"/> is closed. </exception>
  /// <exception cref="T:System.OutOfMemoryException">There is insufficient memory to allocate a buffer for the returned string. </exception>
  /// <exception cref="T:System.ArgumentOutOfRangeException">The number of characters in the next line is larger than <see cref="F:System.Int32.MaxValue"/></exception>
  public override string ReadToEnd()
  {
   return base.ReadToEnd();
  }
 }
}
  • Enable the generation of a code documentation XML file in the project's property window (Build tab) in Visual Studio.
  • Build your solution using the Debug configuration.
  • Create a Sandcastle Help File Builder project named CSharpCodeDoc.
  • Add CSharpCodeDoc.dll and CSharpCodeDoc.XML located in the project's bin/Debug folder to the SHFB project using SHFB's project explorer.
  • Build your SHFB project and view the generated CHM file.

Hands-On Lab 4: Advanced Features For C# Code Documentation

Prerequisites:

  1. Execute Hands-on lab 3 (see above).

Lab step by step description:

  • Add file UsageSamples.cswith C# example code to your project:
    namespace CSharpCodeDoc
    {
     public static class UsageSamples
     {
    #region SwiftReaderClassSample
      public static void ReadSwiftUsingSwiftReader()
      {
       using (var reader = new SwiftFileReader<object>())
       {
        // ToDo: Show how to use the reader here.
       }
      }
    #endregion
     }
    }
  • Change Build Action of UsageSamples.cs from Compile to None.
  • Change documentation of class SwiftFileReader<T>as follows:
    • Note how the previously created example code is referenced.
/// <summary>
/// Represents a reader for SWIFT files.
/// </summary>
/// <typeparam name="T">Parameter type that should be used for reading files.</typeparam>
/// <example>
/// The following example shows how to use the <see cref="SwiftFileReader{T}"/> class:
/// <code source="..\CSharpCodeDoc\UsageSamples.cs" region="SwiftReaderClassSample" lang="C#" />
/// </example>
public class SwiftFileReader<T> : TextReader
{ [...] }
  • Exclude the property Size from documentation by adding an exclude element:
/// <summary>
/// Gets the size of the file.
/// </summary>
/// <value>Size of the file.</value>
/// <exclude />
public int Size { get; private set; }
  • Add a paragraph to the return section of the documentation for the method ConvertFileContent:
    • Note how the see langword element is used.
/// <returns>
/// <para>Returns the file's content as an enumerable.</para>
/// <para>The result contains max. <paramref name="sizeLimit"/> objects.</para>
/// <para>Result will never be <see langword="null"/>.</para>
/// </returns>
public IEnumerable<TDest> ConvertFileContent<TDest>(int sizeLimit)
  • Add a method Dec with two overloads and add documentation to the overloads section in the documentation:
/// <summary>Decrements the number by 1.</summary>
/// <overloads>This method has two overloads.</overloads>
public void Dec()
{
}

/// <summary>Decrements the number by amount.</summary>
/// <param name="amount">The amount to decrement it by.</param>
public void Dec(int amount)
{
}
  • Add file NamespaceDoc.cs with documentation for your namespace to your project:
namespace CSharpCodeDoc
{
 using System.Runtime.CompilerServices;
 
 /// <summary>
 /// Contains sample classes for code documentation.
 /// </summary>
 [CompilerGenerated]
 internal class NamespaceDoc
 {
 }
}
  • Build your project and make sure that there are no errors.
  • Run StyleCop on your project and make sure that there are not errors or warnings.
  • Build your SHFB project and view the generated CHM file. Especially note how the changes you have done to your documentation during this lab changed the resulting compiled help file.

Hands-On Lab 5: Adding Conceptual Content

Prerequisites:

  1. Download latest version of the MAML Guide from http://sandcastlestyles.codeplex.com/releases/view/17333
  2. Execute Hands-on lab 4 (see above).

Lab step by step description:

  • Add content layout using SHFB's Project Explorer
    • Right-click project name, select Add / New Item / Content Layout
    • Add Content Layout.content
  • Open content layout in SHFB with a double click
  • Add conceptual document using SHFB's Content Layout Editor.
    • Right-click in content layout editor, select Add Sibling Topic / Standard Templates / Conceptual
    • Add Overview.aml
  • Right-click Overview in content layout editor, select Toggle Default Topic
  • If not already open, open Overview.amlin SHFB with a double click
    • Option: You can open it you favorite XML editor instead
  • Define the content of the file as follows (don't forget to replace the GUID in the topic id with your guid):
<?xml version="1.0" encoding="utf-8"?>
<topic id="b7b0a984-7cab-4ab7-ba17-39618dfb6feb" revisionNumber="1">
  <developerConceptualDocument xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5" xmlns:xlink="http://www.w3.org/1999/xlink">
    
    <summary>
      <para>SWIFT reader library</para>
    </summary>
    
    <introduction>
      <para>This class libary supports loading of SWIFT documents.</para>
      <autoOutline />
    </introduction>

    <section address="Introduction">
      <title>Introduction</title>
      <content>
        <para>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 
        nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, 
        sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. 
        Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit 
        amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 
        eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. 
        At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd 
        gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</para>
        <alert class="note">
          <para>This is just a placeholder text.</para>
        </alert>
      </content>
    </section>

    <section address="UsageSample">
      <title>How to use</title>
      <content>
        <para>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 
        nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, 
        sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.</para>
        <code language="C#">
          <![CDATA[
var myobj = new SwiftFileReader<object>();
// do something with myobj
myobj.Dispose();
          ]]>
        </code>
        <code language="VB.NET">
          <![CDATA[
Dim myobj = New SwiftFileReader(Of Object)()
' do something with myobj
myobj.Dispose()
          ]]>
        </code>
        <para>Don't forget what we have said in <link xlink:href="#Introduction">Introduction</link></para>
      </content>
    </section>

    <relatedTopics>
      <externalLink>
          <linkText>Homepage of Rainer</linkText>
          <linkAlternateText>time cockpit</linkAlternateText>
          <linkUri>http://www.timecockpit.com</linkUri>
      </externalLink>
    </relatedTopics>
  </developerConceptualDocument>
</topic>
  • Preview help content in SHFB by pressing F5.
  • Add code snippets file using SHFB's Project Explorer
    • Right-click project name, select Add / New Item / Code Snippet
    • Add Code Snippets.snippets
  • Open code snippets file in SHFB with a double click; note how the code snippets are defined (we will not change the generated sample code here).
  • Add conceptual document using SHFB's Content Layout Editor.
    • Right-click Overview.aml in content layout editor, select Add Sibling Topic / Standard Templates / Conceptual
    • Add Details.aml
  • If not already open, open Details.aml in SHFB with a double click
    • Option: You can open it you favorite XML editor instead
  • Define the content of the file as follows (don't forget to replace the GUID in the topic id with your guid):
<?xml version="1.0" encoding="utf-8"?>
<topic id="7e268ef9-b888-4094-bca8-1d51c95f6382" revisionNumber="1">
  <developerConceptualDocument xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5" xmlns:xlink="http://www.w3.org/1999/xlink">

    <summary>
      <para>Details about using the library</para>
    </summary>

    <introduction>
      <para>This document shows how to use the library</para>
    </introduction>

    <section address="Overview">
      <title>Overview</title>
      <content>
        <para>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 
        nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, 
        sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. 
        Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit 
        amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 
        eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. 
        At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd 
        gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</para>
        <para>Note how we use 
        <codeEntityReference qualifyHint="true">T:CSharpCodeDoc.SwiftFileReader`1</codeEntityReference>
        in the examples below. Isn't that cool??</para>
      </content>
    </section>

    <section address="Examples">
      <title>Examples</title>
      <content>
        <para>Here you see some examples</para>
        <codeReference>ClassDefinition#Define</codeReference>
      </content>
    </section>

    <relatedTopics>
      <link xlink:href="b7b0a984-7cab-4ab7-ba17-39618dfb6feb"/>
      <codeEntityReference>T:CSharpCodeDoc.SwiftFileReader`1</codeEntityReference>
      <codeEntityReference>M:CSharpCodeDoc.SwiftFileReader`1.Dec</codeEntityReference>
    </relatedTopics>
  </developerConceptualDocument>
</topic>
  • Preview help content in SHFB by pressing F5.
  • Download the following image into your SHFB project directory:
  • Add bitmap file using SHFB's Project Explorer
    • Right-click project name, select Add / New Item / Bitmap
    • Add image file you downloaded in the previous step
  • Click on the image in SHFB's Project Explorer and change BuildAction to Image in bitmap properties.
  • Change ImageId to TitleImage in bitmap properties.
  • Add image to Introduction section in Overview.aml:
<mediaLink>
<caption>Title</caption>
<image placement="center" xlink:href="TitleImage"/>
</mediaLink>
  • Preview help content in SHFB by pressing F5.
  • Build your SHFB project and view the generated CHM file. Especially note how the changes you have done to your documentation during this lab changed the resulting compiled help file.