About Jolt.NET Libraries

Inspired by the Boost C++ libraries, Jolt.NET aims to complement the .NET Base Class Library (BCL) with algorithms, data structures, and general productivity tools. It is the hope of the authors that the features of Jolt.NET will one day be part of, or represented in the BCL and the .NET Framework.

Thinking About XML Documentation Comments

One of the features for the Jolt 0.2 release is to add support for propagating XML comments for proxy methods in the Jolt.Testing library.  During the past holiday season, I started to dabble in an implementation and consequently started to research what is required to complete this task.  Ideally, I would like to support a syntax that is depicted as follows.


using System;
using System.Reflection;
using System.Xml.Linq;

void ParseXmlComments(Assembly assembly)
{
XmlDocCommentReader reader = new XmlDocCommentReader(assembly);
XNode[] comments = {
reader.GetComments(assembly.GetType("MyType")),
reader.GetComments(assembly.GetType("OtherType").GetMethod("f")),
reader.GetComments(assembly.GetType("OtherType").GetProperty("g")),
reader.GetComments(assembly.GetType("YetAnotherType").GetConstructor(Type.EmptyTypes))
};

XDocument dom = new XDocument("root", comments);
}


The easy part of supporting such an implementation is parsing the XML file so that a MemberInfo or Type object can index a block of XML (the comments).  The rules for doing so are straightforward, and documented in the MSDN help system.

The tricky part lies in the first line of psuedo-code: inferring the location of the XML file from an Assembly object.  XML comments are always installed in a directory that is either very near to, or the same as the installation directory for an assembly.  This is done by convention and facilitates the file's location from Visual Studio's Intellisense.  Given that the Assembly class offers CodeBase and Location properties, it may appear trivial to locate the file.  However these properties do not guarantee finding the reference assembly path for a .NET Framework assembly, which is the path that contains the XML file.  The ".NET Matters" article from MSDN Magazine (June 2004) suggests using RuntimeEnvironment.GetRuntimeDirectory() to locate the reference assembly path, but this fails for .NET 3.0 and .NET 3.5, which use version 2.0 of the common langauge runtime.

Given these issues, I should note that the path inference algorithm using the CodeBase and Location properties will work for assemblies that are loaded from the same directory as the host application.

The following is a summary of my research and conclusions relating to supporting the locating of the XML comments file for an Assembly object.

Reference Assemblies, Location, and CodeBase

The reference assemblies path is the location in which the .NET Framework installer places assemblies (and their XML comments) prior to installing the assemblies in the global assembly cache (GAC).  An IDE or compiler will reference the assemblies from this location, while the runtime will generally load assemblies from another location (i.e. the GAC or the local directory of the running application).  Assemblies from .NET 3.0 and onwards are installed to an explicit reference assemblies directory, but are loaded from the GAC.  For previous .NET Framework versions, assemblies are loaded from the path they were installed to.

The Location path is the location from which an assembly is loaded.  For the .NET Framework assemblies (any version), this is generally going to be the GAC.  For user assemblies, it could be something else (like the local application folder), and a shadow-copied assembly will yield the shadow-copy path in its Location property.

The CodeBase path is the location from which an assembly was first found.  Suzanne Cook gives the example that this path may be an internet URI for a downloaded assembly.  Furthermore, Cook states that the CodeBase property is not guaranteed to be set for a GAC-loaded assembly.

Given these distinctions, it is clear that the reference assemblies path is the ideal path to locate since it will always be the same regardless of how the assembly was obtained or loaded.

Programmatically Locating the Xml Comments File

The CLR has no knowledge of a reference assembly path, so it makes sense that you should not expect a .NET Framework API that knows how to locate the path.  However, during my efforts to find such an API, I came across the MSBuild task ResolveAssemblyReference.  This task will give the physical disk location of the given assembly, the paths to all of its assemlby references, and the paths to any related files.  The related files could be XML, PDB, or any extension that you provide.  Jomo Fisher gives an example of using the managed API for this task to resolve assembly references in his F# code.

I thought this class would solve my problem, but upon closer inspection of the program output you will notice that the XML files are not found, even for assemblies that share the same directory as their XML files (i.e. System.Core.dll).  I tried different configurations of the class, but with no success. 

So, in order to locate the XML comments file for a given assembly, I will have to rely on the technique used by Lutz Roeder's Reflector: search a predefined list of paths, which is expandable with user data.  This has the drawback of needing to update the library each time a new .NET Framework is released (as it may introduce a new reference assembly path), but it is a good short-term fix until I can figure out why the ResolveAssemblyReference class doesn't function as I expect it to.

0 comments: