Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

XMLComments, and large component documentation


:P
On this page:

I was having an interesting discussion about Help Builder with Issam at DataDynamics about the Help creation process for large projects and components. He pointed me a feature in C# (and supposedly also in VB.NET for Whidbey) in the XMLDocumentation mechanism that I had never heard of.

 

In our discussion there a couple of interesting things came up to that I never thought about much. I figured Help Builder sort of as the documentation depository for documentation, so while code comments would be fine and Help Builder can import them either in batch (using an assembly import) or individually by using Help Builder’s add-in. So my thinking has been, that there's not much to worry about by not synching back religiously to the source code. However, the source based XML documentation is vitally important because VS.NET uses XML docs for Intellisense if it’s available.

 

If you didn’t know this make a note of it: Always copy both your assembly and the XML doc file if one is available into the main application that you’re running and debugging in order to get the fully doc'd XML comments with your Intellisense.

 

Anyway, the thing I missed previously to is that there’s an tag which allows storage of XMLComments in an external file, rather than in the source file itself. This works on per class basis and allows externalizing of comments which can be very useful if you plan on documenting extensively within your application. Externalizing the doc content also makes it easier to translate the documentation into other languages (gasp) which would be a bear to do in the source files.

 

The format for this looks like this (all on one line):

 

/// <include file='docs/CommandPrompt_docs.xml'

   path='CommandPrompt_Project/CommandPrompt_Namespace/

        CommandLoader[@name="CommandPromptLoader"]/*' />

 

 

For each member where you’d normally drop a comment you specify an XML file and an XPath string into the XML document to find the node. The syntax for each node should then look identical to the way it looks in comments except you can skip the slashes.

 

Let’s look at a quick example. I actually needed a quick utility today. As I was working with the MS 2.0 Help Compiler and some command line utilities I got sick of constantly popping up a DOS window and changing path. So I created a small Console application that takes a filename as a parameter and opens a console window in the directory of the file. I then stick this into the SendTo folder and whenever I need a command prompt I just right click SendTo command prompt and voila I’m there.

 

Here’s the code simple as it is:

 

using System;

using System.IO;

using System.Diagnostics;

 

namespace CommandPrompt.OS

{

      /// <include file='docs/CommandPrompt_docs.xml'

path='CommandPrompt_Project/CommandPrompt_Namespace/CommandLoader[@name="CommandPromptLoader"]/*' />

      class CommandPromptLoader

      {

            [STAThread]

            static void Main(string[] args)

            {

                  if (args.Length < 1)

                        Process.Start("cmd.exe");

                  else

                  {

                        // *** Change the path and open Command window

                        Environment.CurrentDirectory = GetPath( args[0] );

                        Process.Start("cmd.exe");

                  }

            }

 

           

            /// <include file='docs/CommandPrompt_docs.xml' path='CommandPrompt_Project/CommandPrompt_Namespace/CommandLoader[@name="TestMethod"]/*' />

            public static string GetPath(string FileName)

            {

                  FileInfo fi = new FileInfo(FileName);

                  return fi.DirectoryName;

            }

      }

}

 

With those comment pointers in place you now can create an XML file that looks like this:

 

<?xml version="1.0"?>

<CommandPrompt_Project>

   <CommandPrompt_Namespace>

     

      <!-- Command Loader Class and members -->

      <CommandLoader name="CommandPromptLoader">

      <summary>

      This is the summary document for the CommandLoad class

      </summary>

      </CommandLoader>

 

      <CommandLoader name="TestMethod">

      <summary>

      This is documentation for the TestMethod method.

      </summary>

      <param name="Test">String parameter for testing</param>

      </CommandLoader>

 

   </CommandPrompt_Namespace>

 

   <SomeOther_Namespace>

 

   </SomeOther_Namespace>

  

</CommandPrompt_Project>

 

I purposefully broke this XML out a bit to make it clear that you should very carefully think about how you lay out this XML file, so my preference here would be to use Project/Namespace/Class and member attribute as the way to lay this out. This is not really clear from the sparse documentation.

 

Now keep in mind that this is not really user friendly. First off you need to make sure that the names match which can be hard enough if you use a naming convention. You also need to make sure that the XML doc is valid or everything falls down. And managing text in this way can be tedious as hell. Remember there’s no Intellisense here either. Ultimately this would require a tool of some sort to be really useful.

 

However, because the XML is external to the code file you can create the entries first and then have the Doc team go in and manage updating the documentation without interfering with the source code. It’s also relatively easy to translate here this document since again it is external.

 

Anyway, so now I’m thinking about how I can take advantage of this functionality by providing the ability to backfit content from Help Builder into source code via possibly an external XML file. This would allow generating the content in Help Builder including the easy ability to edit the text in a rich environment that stays in sync.

 

My goal here is to treat Help Builder as the depository for the documentation, rather than the code or even this XML file. Although code and XML may have comments the ‘master’ copy would be in Help Builder. If this is the case Help Builder could then either manually or possibly (not sure yet how to do this) go back and update the documentation into the project.

 

Synching source code with something external is always a bitch. Help Builder links back to source code via member/class signatures based on namespace/class/member/parameters which uniquely identify members in source code. This is how the manual two way tools work when you right click on a member and Help Builder pops up in context. This works until a signature changes and then the link breaks. It can be overridden in Help Builder (the signature is editable) but it’s sort of a hassle, but doable on a single topic merge. However, in a batch situation this gets scary and would probably require explicit prompting whenever a signature cannot be found either prompting to leave it, find a match and resynch or throw it out.

 

I know that that many folks are seriously married to keeping comments all in code, but is this really where you want to do your documentation? Further if you use a tool like Help Builder you can take advantage of the rich interface and the ability to create content that is not directly tied to a say a class or method. For example a topic like a How To or Getting Started topic. But what am I talking about – good documentation is such a rarity these days that it can almost be discounted as non-existent.

 

Any comments on this?


The Voices of Reason


 

Jay Schumacher
September 17, 2004

# re: XMLComments, &lt;include&gt; and large component documentation

One concern with moving the comments out of the source code is that you can potentially impact the readability of the code (without having to switch back and forth to an external entity). However, I think you can mitigate this with good coding standards - where the code becomes more readable itself (better & consistent naming conventions, etc.) and the comments can more easily be lifted out to external documentation.

I definitely like the idea of external documentation - as you mentioned, team developement & documentation becomes far more manageable, as well as team review of documentation. This also increase the chances that power users can learn even more about their business systems by reading through the documentation in a format more accessible to them.

Rick Strahl
September 17, 2004

# re: XMLComments, &lt;include&gt; and large component documentation

Jay, as I was thinking about the getting comments back into code last night some more I realized that this is possibly easy to do after all by going through the code and looking for matching content in Help Builder. I was approaching this the other way around which is a bit tougher.

I think my perfect process would be like this: Start documentation in source code. At somepoint I decide it's time to doc for real and I import into Help Builder (or other doc tool). I continue to document. At some point I decide ok, lets update the source code and it dumps the content created externally back into the source.

Biggest issue there: Size of docs can get very large when you edit in a real environment and dumping that back into code is kind of counterproductive. Nobody wants 20 lines of comments for 5 lines of code <g>. I suppose standards for documenting functionality in non-member topics would solve this, but I like things context sensitive <g>....

Right now the 'automatic' part is missing in Help Builder, but I have a good idea on how to implement that now after these discussions. Manual works, but it requires some discipline. You go to your member in code and to edit you right click, and HB pops up prompting for new topic if it doesn't exist or goes straight to existing topic if it does. Edit in HB, then when done go back to source press Ctrl-F1 and the docs are updated.

I've actually used the manual approach since I put this stuff in and it's easy enough to do that it becomes a habit quickly. In some way I suspect I would continue to work this way even if I could batch back fit.

For batch opoeration the other issue remains synchronizing for changes - changed signatures or dropped methods etc. is tough to do because there's just nothing that uniquely identifies a member. (hmmm... maybe there is a GUID, but I doubt it. How would VS know?)


Issam Elbaytam
September 17, 2004

# re: XMLComments, &lt;include&gt; and large component documentation

I responded to your initial post with a little more explanation in my blog.

Re: Synchronizing.
There is a unique way to identify a member, it is what intellisens uses to look up the members in the xml documentation file. You can see it in the name of each member in the xml file.
name="T|M|F|P:namespace.type.member(paramtypes)"

Rick Strahl
September 17, 2004

# re: XMLComments, &lt;include&gt; and large component documentation

That is basically what I use as the 'signature' in Help Builder. Going backwards from that signature to the code is what's difficult I think. You have to search through the project to find this stuff.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024