Creating a Build Process Plug-In
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.
<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
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.
In the Application tab, set the assembly name and default namespace as you see fit.
In the Package tab, set the NuGet package properties.
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 Pathproperty 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.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 Sandcastle.Core.PlugIn.IPlugIn
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 IBuildProcess
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 Sandcastle.Core.PlugIn.ExecutionContext
object that defines the current execution context. If your plug-in determines that it does not need to run, it
should set the Sandcastle.Core.PlugIn.ExecutionContext.Executed
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
Afterbehavior with theInitializingstep.The
Beforebehavior cannot be used with theInitializing,Canceled, orFailedsteps.The
InsteadOfbehavior cannot be used with theInitializing,Completed,Canceled, orFailedsteps.The
InsteadOfbehavior always takes precedence. The build process will not call any plug-ins withBeforeorAfterbehavior for the step if anInsteadOfplug-in runs. As such, it is up to the plug-in with theInsteadOfbehavior to call the IBuildProcess.ExecuteBeforeStepPlugIns() and IBuildProcess.ExecuteAfterStepPlugIns() methods to run them if needed.If the build step involves creating, modifying, or deleting a non-script file or folder, the
Beforebehavior is always executed prior to creating/modifying/deleting the file or folder. Use theAfterbehavior 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 theBeforebehavior 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
InsteadOfbehavior 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, andCompilingHelpFilesteps will run once for each help file format selected. You can use the IBuildProcess.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
ExtractHtmlInfostep. 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.