Creating a Build Process Plug-In

This topic will walk you through the creation of a plug-in project.

Defining the Plug-In Configuration

The first step is to determine what items will appear in the plug-in configuration. The configuration is stored as an XML fragment in the help file builder project file. The root node is always configuration. Define your own elements to contain the plug-in configuration that will be nested within the root element. When first added to a project, the configuration will be empty. Your plug-in should use appropriate default values as needed. It is possible that a plug-in will have no configurable elements. In that case, there is nothing to add to the default configuration. Below is an example of a configuration that is passed to a plug-in.

Example Plug-In Configuration
<configuration deleteAfterDeploy="true">
  <deploymentLocation id="help1x" location="..\..\SHFB\Deploy\Help\">
    <userCredentials useDefault="true" userName="" password="" />
    <proxyCredentials useProxy="false" proxyServer="">
      <userCredentials useDefault="true" userName="" password="" />
    </proxyCredentials>
  </deploymentLocation>
  <deploymentLocation id="help2x" location="">
    <userCredentials useDefault="true" userName="" password="" />
    <proxyCredentials useProxy="false" proxyServer="">
      <userCredentials useDefault="true" userName="" password="" />
    </proxyCredentials>
  </deploymentLocation>
  <deploymentLocation id="helpViewer" location="" renameMSHA="false">
    <userCredentials useDefault="true" userName="" password="" />
    <proxyCredentials useProxy="false" proxyServer="">
      <userCredentials useDefault="true" userName="" password="" />
    </proxyCredentials>
  </deploymentLocation>
  <deploymentLocation id="website" location="..\WebHelp\SHFB\">
    <userCredentials useDefault="true" userName="" password="" />
    <proxyCredentials useProxy="false" proxyServer="">
      <userCredentials useDefault="true" userName="" password="" />
    </proxyCredentials>
  </deploymentLocation>
  <deploymentLocation id="openXml" location="">
    <userCredentials useDefault="true" userName="" password="" />
    <proxyCredentials useProxy="false" proxyServer="">
      <userCredentials useDefault="true" userName="" password="" />
    </proxyCredentials>
  </deploymentLocation>
</configuration>

Creating the Project

This section describes how to create and configure the build process plug-in project. It will describe the process for a C# project but the steps should be fairly similar for a VB.NET project with a few differences in the configuration option titles.

Create the Plug-In Project

  1. In Visual Studio, select the New Project option. In the New Project dialog box, select the C# or VB.NET language, and then select the Documentation subcategory. Select the Sandcastle Help File Builder Plug-In template, give it a name and click OK to create it. Once it has been created, right click on the project and select Properties.

  2. In the Application tab, set the assembly name and default namespace as you see fit.

  3. In the Package tab, set the NuGet package properties.

  4. By default, the Debug project properties are set to use the standalone GUI for debugging which will help you see if the component can be located, that the configuration form is working if you created one for the component, and that it is working within the build as expected. See the Debugging Components and Plug-Ins for some special requirements when debugging components and plug-ins.

      Tip

    Using the standalone GUI as the host is easier than using Visual Studio as the package locks the assemblies once the help file builder project has loaded them for use and you will not be able to rebuild them. Shutting down the standalone GUI frees the assemblies so that you can rebuild them and start a new debugging session.

    In the help file builder project that you use to test your plug-in, set the project's Component Path property to the folder containing your build component's assembly. If you have opened the project's Components property page before setting the component path, you may need to close and reopen the project in order for it to discover your build component assembly.

  5. Optionally, select the Signing tab and check the "Sign the assembly" checkbox. Select "<New...>" from the "Choose a strong name key file" dropdown, enter a filename, and click OK to create the key file. You can protect the key file with a password if you like or uncheck the option to create one without a password.

The Plug-In Template Class

You are now ready to edit the plug-in class itself. See the comments in the template class for information on how to get started. Some general information is given below. Note that multiple plug-ins can reside within the same assembly. Add new class files to the project and implement the necessary methods as described below and as shown in the template class.

The plug-in is derived from the SandcastleBuilder.Utils.BuildComponentIPlugIn interface and consists of a few properties and methods that you must implement. These are described below. Review the code for "TODO:" comments to find sections that need attention such as setting the plug-in's ID, defining the execution points, etc. If you followed the steps in the Creating the Project section, you can run the project and debug it by setting breakpoints in the plug-in's code. As noted above, set the test project's Component Path property to the folder containing the plug-in assembly first. If necessary, close and reopen the test project so that it can discover the plug-in.

The Export Attribute Metadata

The plug-in is a Managed Extensibility Framework (MEF) component. The HelpFileBuilderPlugInExportAttribute is used to define the necessary metadata that enables the help file builder to load and use the component.

Id

The Id parameter is required and is used to uniquely identify the plug-in.

Version

The Version property is optional and allows you to define the plug-in version displayed in the help file builder property page when the plug-in is selected.

Copyright

The Copyright property is optional and allows you to define the plug-in copyright displayed in the help file builder property page when the plug-in is selected.

Description

The Description property is optional and allows you to define the plug-in description displayed in the help file builder property page when the plug-in is selected.

RunsInPartialBuild

The RunsInPartialBuild property is optional and allows you to define whether or not the plug-in runs during a partial build. Partial builds occur when generating the reflection data for the namespace comments and API filter editor dialogs. In such cases, the plug-in may not be needed. If this property returns false, the default, the plug-in is omitted which can speed up the partial build. Set it to true if your plug-in adds information needed for the reflection data or namespace comments.

IsHidden

The IsHidden property is optional and allows you to define whether or not the plug-in is hidden and does not appear on the project property page. If false, the default, the plug-in will appear on the property page. If true, the property page will not list it as one that can be added to the project. This is useful for presentation style dependency plug-ins that have no configurable elements and thus do not need to be manually added to the project to override settings.

The Plug-In Interface

The interface consists of one property and four methods.

ExecutionPoints

The ExecutionPoints property is probably the most important member of the interface. It returns a collection of ExecutionPoint objects that define at which steps in the build process the plug-in should be ran. Execution points can be set to run before and/or after a build step to supplement the default processing or they can be set to run instead of the build step to completely suppress or replace the default processing. See the BuildStep enumeration for a list of the defined build steps.

Each execution point can be assigned a priority. The execution priority is used to determine the order in which the plug-ins will be executed. Those with a higher priority value will be executed before those with a lower value. Those with an identical priority may be executed in any order within their group. If not specified, a default priority of 1,000 is used.

Initialize

The Initialize method is used to initialize the plug-in at the start of the build process. It is passed a reference to the current BuildProcess and an XPath navigator containing the plug-in configuration. You should cache a copy of the build process reference for use during execution as it contains many properties and methods that you will find useful.

Execute

The Execute method is called to perform the plug-in processing during the relevant build steps. It is passed an SandcastleBuilder.Utils.BuildComponentExecutionContext object that defines the current execution context. If your plug-in determines that it does not need to run, it should set the ExecutionContextExecuted property to false. This is especially important for plug-ins with the InsteadOf behavior. If none run, the default processing will occur.

Finalizer and Dispose

The Dispose method can be used to dispose of any resources used during the build process. If you do not have any resources that need to be disposed of, this method can be left as it is and the finalizer method can be removed.

Execution Notes

There are certain conditions to be aware of when choosing and coding the execution behavior for your plug-in.

  • The earliest execution point for a plug-in is the After behavior with the Initializing step.

  • The Before behavior cannot be used with the Initializing, Canceled, or Failed steps.

  • The InsteadOf behavior cannot be used with the Initializing, Completed, Canceled, or Failed steps.

  • The InsteadOf behavior always takes precedence. The build process will not call any plug-ins with Before or After behavior for the step if an InsteadOf plug-in runs. As such, it is up to the plug-in with the InsteadOf behavior to call the ExecuteBeforeStepPlugIns and ExecuteAfterStepPlugIns methods to run them if needed.

  • If the build step involves creating, modifying, or deleting a non-script file or folder, the Before behavior is always executed prior to creating/modifying/deleting the file or folder. Use the After behavior if you need to guarantee that the file or folder exists or you do not want your version overwritten. The exceptions to this rule are MSBuild project files (*.proj) and MRefBuilder.config which are always created prior to running the Before behavior plug-ins. This allows you to modify the script files prior to them being ran.

  • If the build step involves creating, modifying, or deleting a script file or folder and the InsteadOf behavior is used, the plug-in is responsible for creating the script file/folder. All normal processing involving the file/folder including its creation is skipped.

  • The GenerateHelpFormatTableOfContents, GenerateHelpFileIndex, GenerateHelpProject, UpdateTableOfContents, and CompilingHelpFile steps will run once for each help file format selected. You can use the CurrentFormat property to determine the current help file format being built in order to skip or alter the plug-in's processing based on the help file format.

  • Be aware that the HTML Help 1 index and table of contents files and the website table of contents file are actually generated as part of the ExtractHtmlInfo step. However, the before and after plug-in behaviors for the index and table of contents steps in each of those formats will still be executed.

See Also