BuildAssembler (EXE)

I my previous blogs I discussed MrefBuilder and Sandcastle.config in detail. Sandcastle process uses three executables:

  • MRefBuilder: Reflects over managed assemblies to produce an XML-formatted reflection information file.
  • BuildAssembler: Collates information from comment files and reflection information files into a set of HTML pages.
  • XslTransform: Applies XSL transforms to XML files. This executable is used to generate and manipulate auxiliary data files.

Sandcastle architecture uses a configurable build component stack. As each topic is build, it is represented as an in-memory XML document. The document is passed through a stack of build components, each of which can act on the document in any way. The component stack is specified in Sandcastle.config file, and the set of topics to be generated is specified in a manifest. A simple component stack that might be used to generate API reference documentation is shown below:

  1. Load reflection data

  2. Load authored comments

  3. Execute an XSL transform

  4. Save the document

BuildAssembler (EXE)

BuildAssembler controls the component stack at the center of Sandcastle. The command-line inputs for BuildAssembler are simple:

BuildAssembler manifest /config:config

The manifest is a list of topics to build, and the Sandcastle.config file defines the BuildAssembler component stack.

The manifest has a simple XML structure that defines a list of topics.

<topics>

<topic id=”string” />

<!-- more topic elements -->

</topics>

A manifest may contain any number of topic elements; each topic element must have an id attribute. Although BuildAssembler does not require it, we expect that GUIDs will be used for conceptual topic IDs and CERs will be used for reference topic IDs.

Sandcastle.config file is structured as follows:

<configuration>

<dduetools>

<builder>

<components>

<component type=”type” assembly=”path”>

<!-- component configuration data -->

</component>

<!-- more component elements -->

</components>

</builder>

</dduetools>

</configuration>

Any number of component elements is allowed. Each component element must specify an assembly from which to load the component and a fully qualified type name corresponding to a BuildComponent class. A component element may have an arbitrary descendent structure that specifies configuration information for the component. Note that this allows different instances of the same component to be used for different purposes, even within the same component stack, by providing different configuration data.

BuildAssembler instantiates each component by pointing its constructor to its section of the configuration file. Once the component stack has been instantiated, BuildAssembler invokes the component stack for each topic specified in the manifest.

Note that what occurs during a component stack invocation is entirely up to the individual components in the stack. Depending on the components and their configuration, nothing may occur, or the XML or HTML document is saved corresponding to a topic.

As it reads the configuration file and manifest file, BuildAssembler may report any of the following error conditions:

Condition

Description

IO

The configuration (or manifest) file was not found, or is not accessible.

XmlException

The configuration (or manifest) file is not well-formed.

XmlSchema

The configuration (or manifest) file does not fulfill the required schema.

We refer to these error conditions as the “file reading errors”; other tools that read XML files may also produce them.

During the component instantiation phase, BuildAssembler may report any of the following error conditions:

Condition

Description

IO

The specified component assembly was not found, or is not accessible.

BadImageFormat

The specified component assembly is not a managed DLL.

TypeLoad

The specified component assembly does not contain the specified component type.

MissingMethod

The specified component type does not define the appropriate constructor.

TargetInvocation

An exception occurred while the specified component was being instantiated.

InvalidCast

The specified component is not a BuildComponent.

When it reports these errors, BuildAssembler also reports which component generated the error. We refer to these errors as the “dynamic loading errors”; other tools that dynamically load type from external assemblies may also produce them.

During the component stack invocation phase, BuildAssembler may report any error that occurs within a build component. When it does so, it also reports which component generated the error.

Within the BuildAssembler code, build components are represented by the following abstract class:

public abstract class BuildComponent {

protected BuildComponent (XPathNavigator configuration) {}

public abstract void Apply (XmlDocument topic, string id);

protected void WriteMessage (LogLevel level, string message) {}

}

To instantiate each build component, the constructor is called with the configuration parameter set to the build component’s section of the configuration file. For each topic, the Apply method of each build component is called in turn with topic parameter set to the XML document as modified by previous components and the id string equal to the id of the topic being generated. Build components can write messages to the log by calling the WriteMessage method.

To create a new build component, a developer just creates a new class that inherits from BuildComponent, and compiles his/her source with a reference to the BuildAssembler executable, which defines the abstract BuildComponent class:

csc /t:library MyComponent.cs /r:BuildAssembler.exe

He/she can then use the new component in the BuildAssembler configuration file without having to re-compile the BuildAssembler application.

BuildComponents (DLL)

The build components we ship fall into three categories: action components that affect the document, flow control components that affect the order of invocation of other build components, and diagnostic components that can be used to supply information about the state of the XML document that represent the topic at any point in the component stack.

Action

Flow Control

Diagnostic

CopyFromFile

CopyFromDirectory

CodeExample

Transform

SharedContent

ResolveLinks

Save

ForEach

IfThen

Switch

Branch

Display

Validate

Anders Ljusberg explains in detail how Sandcastle works and has provided some details about these components. I will write a separate blog with details about these components.