User Documentation

Contents

Introduction

Gauntlet is a .NET code generation tool with emphases on simplicity, extensibility, and seamless integration with the .NET build system. It is designed to slot right into your build process, alleviating you of the need to run an external tool for code generation.

Why Another Code Generation Tool?

There is a plethora of code generation tools available for .NET, some commercial and some – like Gauntlet – open source. Why is there a need for another?

Gauntlet differs from other code generators by integrating seamlessly with .NET’s build platform, MSBuild. What this means is that when you change an input or template file, you simply build your project to have the corresponding output generated. This works the same whether you’re building from the command line or from within Visual Studio. There is no need to start up an external tool, or even to know that Gauntlet is being used to generate the output.

Gauntlet also provides extensibility points for the entire generation process. If you need to support a custom input format, you can. If you need to integrate with a proprietary template engine, you can.

How Might I Use Gauntlet?

The possibilities really are endless, but here are some examples to illustrate:
  • Ever wanted more control over the web service clients that Visual Studio generates for web references? Using Gauntlet you could write your own template and take full control of the code, using the WSDL as the input to the generation process.
  • Most domain layers are very repetitive: they’re essentially a bunch of data classes with some business logic sprinkled throughout. Using Gauntlet, you could define a template for your domain objects and save a heap of time and maintenance cost. Your input file could be a simple XML structure defining the properties of your domain object. The template could contain the logic to generate fields, properties, property change notifications (for data binding), custom serialization logic (to increase serialization speeds) etcetera.
  • Ever had to work with a framework that imposes ridiculous restrictions that stop you from using inheritance to factor out common functionality? cough** MAF cough** Well, you could succumb to the evil will of the framework and write the same code a hundred times, or you could write a template and generate that code instead.

Design

Assemblies

Gauntlet’s key components are divided into two assemblies: Kent.Boogaart.Gauntlet and Kent.Boogaart.Gauntlet.MSBuild. The former defines the core Gauntlet interfaces and provides some generic implementations of these interfaces. The latter provides support for incorporating Gauntlet into MSBuild scripts.

If you’re writing custom components to hook into the Gauntlet generation process, you’ll need to reference Kent.Boogaart.Gauntlet.dll. If you’re simply using Gauntlet in your build process, both assemblies are used and the instructions for setting up can be found here.

Generation Process

Gauntlet’s code generation process is depicted below:
CodeGenerationProcess.png

The input and template files are fed into a regeneration policy. The regeneration policy decides whether the generation should continue or be skipped altogether. If continued, an input translator is used to translate the input file into something that can be consumed by the output generator. The output generator is responsible for converting the translated input into the final output file. A context is passed through the whole generation process. This context can be used by the various components of the pipeline to make decisions or store state.

All pipeline components are extensible. You can provide your own regeneration policy, input translator, output generator, or even a custom context implementation. Gauntlet comes with various useful implementations of all of these components and it will often be unnecessary for you to write your own, but the extensibility points are there if required.

Missing from the above diagram is a depiction of logging. The context passed through the generation process includes a property of type Kent.Boogaart.Gauntlet.ILog. This interface defines methods for logging messages and exceptions, and can be used by components in the generation pipeline. The particular implementation of ILog present will determine how log entries are manifested. When using Gauntlet from within your MSBuild script, log statements will flow through to the build output. Therefore, if an error is logged, it will appear as an error when building from within Visual Studio.

Using Gauntlet

Integrating With MSBuild

In order to integrate Gauntlet into your build process, you need to follow a number of simple steps. As of version 1.0 of Gauntlet, there is no Visual Studio integration. Therefore, these steps must be performed manually. Note that you can still build from Visual Studio (since Visual Studio uses MSBuild behind the scenes). However, there is no Visual Studio add-in to perform the steps below automatically.

There is a sample solution called IntegratingGauntletWithMSBuild.sln that shows the results of all these steps being applied. Inside this solution there is a single project called ConsoleApplication, which uses Gauntlet to generate an enumeration called GeneratedEnum. When the application is executed, it outputs the members of this enumeration to the console.

Ensure Gauntlet Files are Available to Build Process

First of all, make sure that the Gauntlet files are available to your build process. An easy way to do this is to place them under a Lib (or similar) directory in your project’s folder structure. I normally have a Lib folder to store referenced assemblies anyway, so I just create a Lib\Gauntlet folder to store the Gauntlet assemblies. You can see this in the sample:
FolderStructure.png

There are a number of files that need to be placed in this folder: Kent.Boogaart.HelperTrinity.dll, Kent.Boogaart.Gauntlet.dll, Kent.Boogaart.Gauntlet.MSBuild.dll, Gauntlet.targets, and NVelocity.dll:
GauntletFiles.png

Import Gauntlet into Relevant Project(s)

The next step is to determine which projects in your solution need to use Gauntlet, and to import Gauntlet targets into their build script. This requires the addition of an <Import/> element in the MSBuild file. For example, the ConsoleApplication.csproj file includes this:
<Import Project="..\Lib\Gauntlet\Gauntlet.targets" />

Define Templates

Next, add a template to your project. If you’re using the NVelocity output generator (more on this later) then the template just needs to be a text file that contains an NVelocity template. The sample project contains a file called GeneratedEnum.template, which is responsible for converting the input into an enumeration. The contents are as follows:
namespace ConsoleApplication
{
	public enum GeneratedEnum
	{
		#foreach ($member in $GeneratedEnum.Members.Member)
			$member.Name,
		#end
	}
}

Define Input File

Now that we have a template, we need to add a file to serve as input to the code generation process. In this case, we’re using Gauntlet’s built-in XML input translator, so the input file – which I called GeneratedEnum.input – is in an XML format. The contents of this file are:
<?xml version="1.0" encoding="utf-8" ?>

<GeneratedEnum>
	<Members>
		<Member Name="One"/>
		<Member Name="Two"/>
		<Member Name="Three"/>
	</Members>
</GeneratedEnum>

Generate the Output File

Now that we have both template and input files, we need to tie the two together to produce the output file. To do this, we need to edit the project file manually. Open the project file and locate the input file’s entry. Change its type from None to GeneratedItem:
<GeneratedItem Include="GeneratedEnum.input" />

Next, include the details of the template file, output file, input translator, and output generator inside the item definition:
<GeneratedItem Include="GeneratedEnum.input">
	<TemplateFile>GeneratedEnum.template</TemplateFile>
	<OutputFile>GeneratedEnum.g.cs</OutputFile>
	<InputTranslator>Kent.Boogaart.Gauntlet.InputTranslators.XmlInputTranslator, Kent.Boogaart.Gauntlet</InputTranslator>
	<OutputGenerator>Kent.Boogaart.Gauntlet.OutputGenerators.NVelocityOutputGenerator, Kent.Boogaart.Gauntlet</OutputGenerator>
</GeneratedItem>

Without this information, the build process will fail with an appropriate error. That’s because Gauntlet attempts to process any files that are GeneratedItems.

Include the Output File

Once the above step is complete, build your project. All being well, you should see the output file in your project’s folder. Note that the build may fail, but the output file should still be generated. That’s because the output file has not yet been included into your project, and the Program class is assuming the existence of a GeneratedEnum type, which is defined by the output file.

An easy way to include the output file in the solution is from Visual Studio’s solution explorer. First, click show all files for the project (the highlighted icon below):
ShowAllFiles.png

You will then see the GeneratedEnum.g.cs file:
ShowAllFiles2.png

Right-click the file and choose Include In Project:
IncludeInProject.png

Now the output file is included in the project. If you execute the project, you should see all the members of the enumeration listed. Try playing with the input file and re-executing the application.

Out-of-the-box Functionality

This section discusses the functionality that Gauntlet provides out-of-the-box.

XML Input Translator

The Kent.Boogaart.Gauntlet.InputTranslators.XmlInputTranslator class is an input translator that takes any XML document and places in the current context for consumption by the output generator. It uses the root of the XML document as a key under which the XML is stored. From there, it permits a simple property syntax to navigate the XML document.

For example, suppose you have the following XML input:
<?xml version="1.0" encoding="utf-8" ?>

<BusinessObject ClassName="Customer" Namespace="BusinessObjects">
	<Properties>
		<Property Name="Name" Type="string"/>
		<Property Name="DOB" Type="DateTime"/>
		<Property Name="Address" Type="string"/>
	</Properties>
</BusinessObject>

Using the NVelocity output generator (see below), the class name can be accessed via the syntax $BusinessObject.ClassName and the collection of properties can be obtained via the syntax $BusinessObject.Properties.Property.

NVelocity Output Generator

The Kent.Boogaart.Gauntlet.OutputGenerators.NVelocityOutputGenerator class is an output generator that assumes the template file is an NVelocity template. It takes all items in the Gauntlet context’s state bag and passes them into the NVelocity context for the template to consume.

Timestamp Regeneration Policy

The Kent.Boogaart.Gauntlet.RegenerationPolicies.TimestampRegenerationPolicy class is used by default, and uses the timestamps of the files to determine whether code generation is required.

Forced Regeneration Policy

The Kent.Boogaart.Gauntlet.RegenerationPolicies.ForcedRegenerationPolicy class is a regeneration policy that always generates code, regardless of whether the generation is actually necessary. It should be used with caution.

Default Context

The Kent.Boogaart.Gauntlet.Context is a base context implementation that is used unless otherwise specified. It includes properties to get the various files included in the generation, a timestamp for when the generation process began, a log, and a state bag.

Last edited May 18, 2008 at 3:07 PM by kentcb, version 5

Comments

No comments yet.