In this post I will show how to document a Dynamics CRM 2011 custom workflow activity assembly and use Doxygen to generate a compiled HTML (CHM) help file. (Doxygen can actually generate documentation in a variety of different formats, but I'm partial to CHM files because they're entirely self-contained.) For this example, I have a project that consists of these three C# files:
And the final output will be this generated CHM file: LucasWorkflowDemo.chm (76.94 kb).
Although this sample is focused on documenting an assembly that is used as part of a Dynamics CRM solution, the overall documentation approach and techniques are applicable to any C# project.
Before we look at how to document code using Doxygen, let's step back and take look at the broader problem we need to solve. Put simply, getting software documented properly after it's written is a pain.
Developers typically don't enjoy preparing documentation, and even if you can get them to document it initially, keeping it updated is always a challenge. (True story - as a brash young developer, I was quick to irritate a business analyst on my team by telling him things like "documentation costs extra.") If you think about it, this lack of desire to document code kind of makes sense. First, in most situations where code isn't being packaged and sold, anybody who needs to work with something that's already been written will likely have access to the source code (including comments), so formal documentation isn't absolutely necessary. Second, a typical developer has better coding skills than writing skills.
The reasoning - excuse, really - of the first point fails spectacularly when we look at Dynamics CRM custom workflow activities. When a developer prepares these, the people who work with the activities later may very well not have access to the source code, and even if they do, they may not fully understand it. For example, think of a situation in which you have primarily functional consultants building workflows. If they don't have good documentation of what a custom workflow activity does and the inputs it expects, they're likely to get unexpected results when using it.
But assuming you convince your developers of the need to generate documentation, you may still have a problem in that it's not something that comes easily to them, so how can you make it easier? The obvious answer is to generate documentation based on the source code itself, and that's where Doxygen comes in.
From the Doxygen website:
Doxygen is the de facto standard tool for generating documentation from annotated C++ sources, but it also supports other popular programming languages such as C, Objective-C, C#, PHP, Java, Python, IDL (Corba and Microsoft flavors), Fortran, VHDL, Tcl, and to some extent D.
What this means is that if you can get your developers to comment their code, you can generate a decent body of documentation.
The rest of this post is split into three sections:
- Commenting the code
- Generating the initial HTML output
- Generating the final compiled HTML output
Commenting the code
The first step, and maybe the hardest if you have to convince recalcitrant developers to go along, is to document the code. Doxygen supports multiple formats for the comment blocks it uses to generate documentation (Javadoc, Qt, C# XML, etc.), but because Visual Studio has native support for C# XML comments for classes and class members, I recommend using it. If you have XML documentation comments enabled via the Tools->Options menu, starting a new line immediately above a class or member definition and typing "///" will cause Visual Studio to create a stub XML documentation comment. The stub for a class, field or property will simply be:
/// <summary>
///
/// </summary>
and you would fill in a brief description in the line in the middle.
The stub for a method includes the summary block as above, but also lines for the parameters and return value (if they exist), so this silly example method:
public string DoThis(string s1, string s2, out string s3)
{
s3 = "something";
return "hi";
}
would get the following comment stub generated:
/// <summary>
///
/// </summary>
/// <param name="s1"></param>
/// <param name="s2"></param>
/// <param name="s3"></param>
/// <returns></returns>
In addition to making Doxygen documentation generation possible, commenting your code this way is what lets IntelliSense provide parameter information in Visual Studio, so your team should already be doing it.
I have found that simply filling out the Visual Studio-generated stubs usually gives me excellent results, but the C# language specification defines a number of additional XML documentation comment tags. Here is a link to the complete list of XML tags that Doxygen supports: http://www.stack.nl/~dimitri/doxygen/manual/xmlcmds.html.
Two additional notes about Doxygen:
- By default Doxygen does not document private members, so these will not show up in your generated documentation even if you comment them. You still should comment private members for IntelliSense support.
- Doxygen only generates documentation based on the comment and the member name, so attribute decorations like "Output" or "Input" will not be automatically included in your generated documentation. Because the actual users of a custom workflow assembly will see the names specified in the attribute decorations, I like to include that in the documentation comment along with the description.
Generating the initial HTML output
Once your code is documented, it's time to actually run Doxygen. If you haven't already downloaded and installed it yet, you can download a Windows binary from http://sourceforge.net/projects/doxygen/files/snapshots. For this example, I am using Doxygen 1.8.3.
As with most great open source tools, you can run Doxygen from a command line, but there's also a GUI frontend called Doxywizard that is included in the Windows binary package. There are tons of settings you can adjust in Doxygen, so I'm going to show a vanilla output to HTML and prep for CHM conversion walk through using the Doxywizard Wizard tab:
- Set up your basic settings.
- Set up your mode options. Here you can tell Doxygen whether to generate documentation for all members or just commented ones. You can also include cross-referenced source code in the documentation.
- Select your output format. Finer control over the output formats is available on the Expert tab.
- Set your diagramming options. I usually leave these alone.
- Finally, select the Run tab and click "Run doxygen" to generate your output.
If all went according to plan, you should now have a set of documentation files created in the destination directory you specified in step 1. Here's what my HTML class list page looks like:
Once you're happy with the basic options you've specified, make sure to save your Doxygen project definition via the File->Save menu. That will let you generate updated documentation later without having to re-enter all your configurations.
Generating the final compiled HTML output
The final step that remains is to create the CHM help file. To do that you will need to have Microsoft HTML Help Workshop installed on your system. If you don't already have it, you can download it from http://www.microsoft.com/en-us/download/details.aspx?id=21138.
After you have verified that Microsoft HTML Help Workshop is installed, go to the Expert tab in Doxywizard and select HTML from the Topics list. On the screen that appears to the right, scroll down until you see the three options that start with GENERATE_HTMLHELP like what's circled in the screenshot below:
- Make sure GENERATE_HTMLHELP is checked.
- Specify the name of the CHM file you want generated. If you type just a name, the file will be created in the same directory as the rest of the HTML files. If you specify a full path, the file will be created there.
- Tell Doxygen where hhc.exe is located. On my system it's located at C:\Program Files\HTML Help Workshop\hhc.exe.
Finally, go to the Run tab and click "Run doxygen" to re-generate the HTML output along with the CHM help file.
As before, make sure you save your project, and you're all set. Happy coding (and documenting)!