Click here to Skip to main content
11,924,995 members (55,774 online)
Click here to Skip to main content
Add your own
alternative version


22 bookmarked

Genuilder - Build Time Development Framework

, 29 Nov 2011 Ms-PL
Rate this:
Please Sign up or sign in to vote.
Generate, verify, modify code files automatically during the build process of your projects.

Table of contents


This article has almost the same content as Genuilder's documentation. But CodeProject members are not developers like other... We are curious, we hack, combine, create, criticize ideas in order to find better solutions, for ourselves and for others. That's why I'll also talk about the implementation details of Genuilder at the end of this article.

In one sentence, Genuilder is a Build time development framework... Remember, it took me a long time to find how to describe Genuilder in one sentence. It means that you will be able to run your own code when developers build your project, emit error messages, generate code on the fly (for example, it is how WCF RIA services works), and more.

...or you can just use the built-in features, like AppConfig compile time verification, or async contract generators for WCF.


Go to and download the Genuilder Visual Studio extension.

Run it.


Restart Visual Studio, you should then see the new project item.


Upgrading Genuilder

You have to uninstall the previous version of Genuilder in the Extension Manager (in Visual Studio "Tools/Extension manager").


Common features

Common features are accessible through the CommonFeature enumeration in your Genuilder project.


You need to run your Genuilder project each time you modify it to install or remove features from your projects.


AppConfigVerifier is an integration in Genuilder of this project. It scans all 'type=".*"' in the config file and checks if the type is referenced in the project. The documentation can be found on CodeProject. Here is a quick example, where in the config file you misspelled the MembershipProvider type:


Genuilder will find the error at compile time:


You can exclude types or assemblies from the verification, just check this article.


This feature comes from one of my articles on CodeProject. With it you can access your AppSettings and ConnectionStrings in a strongly typed way. For example, the AppConfig:


Auto completion on AppSettings:


Auto completion on ConnectionStrings:



EnvironmentFile is just a pre-processor for your config file. For example, you have this app.config with a token:


You also have this EnvironmentFile.env file which is just a key=value pair list delimited by line breaks:


After compilation, the output config file (for example, MyProject.exe.config) will be:


This is particularly useful when developers in a team do not have the same development environment, they don't need to checkout their own version of the app.config. (EnvironmentFile should be unique for each developer and should not be in your source control.)

If one of your fellow developers changes the config file like that:


After the next Get latest version, the project will not compile because the new token is not set in EnvironmentFile.env:



InterfaceExtractor is a code generator which extracts an interface from public members of classes and structs. This feature is really useful when you want to create static or dynamic proxies around a service or a controller for authentication or logging for example. Here is some other cool things to do with an interface. For example, this class:


will create extract this interface:


Note that the parameter of ExtractInterface is optional, the default interface name is IClassName. Also, you don't have to implement the interface on your class.

Warning: [ExtractInterface(typeof(SomeNamespace.Interface))] is currently not allowed, you cannot specify the namespace of the extracted interface... not a big deal to add though.


Like InterfaceExtractor, PropertiesExtractor is a class generator which generates a static class to access property names in a strongly typed way. For example, this class implements INotifyPropertyChanged and does not hard code the property name with a string:


Because PropertiesExtractor will generate this other class:


This way if you refactor the property name, the code will break at compile time instead of during runtime.

As with InterfaceExtractor, the parameter of the ExtractProperties is optional, the default class name is ClassNameProperties.

Warning: [ExtractProperties(typeof(SomeNamespace.MyClassProperties))] is currently not allowed, you cannot specify the namespace of the extracted class properties... not a big deal to add though.


This feature generates a class to access your configuration file in a strongly typed way. If you remove a section from your config file and somewhere your code has a dependency on it, it will break at compile time.

For example, for this config file:


You will be able to access sections like this:



Installing an extension in your project

An article has been written on CodeProject to introduce the Extensibility framework of Genuilder, but I will refresh your memory. To install an extension, you need to use ExtensibilityFeature, add extensions, and install it on the project. In this example, you install AsyncServiceContractsExtension on the file Program.cs of every project.


Built-in Extensions


This extension creates a ServiceContract given a synchronous ServiceContract, useful for Silverlight projects. Given:


Will generate:


An example is given here.


It generates classes to access a type's member in a strongly typed way. Given:


It will generate a class to access PropertyInfo, MehtodInfo, EventInfo this way:



The goal and usage of this IExtension is explained in this CodeProject article.

Custom Extensions

Object model

To create your own extension, you have to implement IExtension, here is the object model of Genuilder.Extensibility:

GenItems represents code files of your project, you can use ExecutionContext.CreateChild(string name) and GenItem.CreateChild(string name) to create new ones. When you use GenItem.CreateChild, the child will be deleted when the parent is deleted.

MSBuild logging

You can easily send warning, error, and info messages to Visual Studio by using ExecutionContext.Logger and GenItem.Logger. For example, in this example, I output an error on Program.cs line 5 column 6 in Visual Studio.


Once installed on my project, here is what happens at compile time:


Debugging an Extension

You can easily debug your extensions by calling the Project.Build() method on your project.


In this case, you will be able to break in the MyExtension class to see what is going on during the build.

Easy code parsing and generation

Genuilder has a built-in object extension to easily parse CodeItems with NRefactory.


You can get it this way:

var compilationExtension = genItem.GetExtension<CompilationUnitExtension>()

Then you can use the CompilationUnit property to walk through the Abstract Syntax Tree (AST). Or, more easily, use the Visitor pattern by implementing AbstractASTVisitor, overriding methods called during the visit of the tree, then calling CompilationUnit.Visit(visitor,null);. Take a look at the code source of ProxyGeneratorExtension.

In this example, you'll see how to use the CodeWriter class to generate readable code.



Currently, the intellisense of Resharper doesn't work on generated classes. But the code will compile.

Under the hood: All is feature

In Genuilder philosophy, all is feature and features are... Chunk of MSBuild XML in your project, nothing more, nothing else. And there is actually two types of features.

Under the hood, a CommonFeature is just a TargetFeature, as you can see in the implementation of InstallCommonFeature.

public void InstallCommonFeature(CommonFeature feature)
    InstallFeature(new TargetFeature(
       GetFullPath(_CommonFeature.GetFileName(feature), feature)));

For example, when you install a CommonFeature and an IExtension in your project:

foreach(var project in Projects.InSubDirectories("../..").ExceptForThisAssembly())
    var ex = new ExtensibilityFeature();
    ex.AddExtension(new MyExtension());

You will see in the csproj file the following XML :

Red elements are the delimiters of Genuilder's sections. Genuilder guarantees that everything it adds to your csproj is between these two elements.

Blue is the extensibility feature's section.

Cyan is your extension section, composed in three parts delimited by pipe '|' parts:

  • The full class name of your extension
  • The assembly of your extension
  • The DataContract serialization of your extension

Orange we ask to not use the Visual Studio compiler. Without it, auto completion on generated classes is buggy.

Green is the CommonFeature's section, as you can see it only includes an import to a target file.

A feature is really easy to implement, I use the MSBuild framework along with some of my own Extension Methods to modify the csproj file easily.

You can use the msBuildData parameter to add things just after the Genuilder's section delimiter; for example, this is how TargetFeature is implemented:

public override void LoadFeature(Project project, MSBuildData msBuildData)
    var importPath = PathUtil.RelativePathTo(
        new FileInfo(project.Path).Directory.FullName, 
        new FileInfo(_Path).FullName);

MSBuild integration of Extensions

As you can see in the Blue section, the Extensibility feature imports Genuilder.Extensibility.targets.

It just inserts its own Msbuild Task during compilation, and during cleaning.

<Project xmlns="" ToolsVersion="3.5">
    <UsingTask TaskName="Genuilder.Extensibility.MSBuild.ExtensibilityTask" 
    <UsingTask TaskName="Genuilder.Extensibility.MSBuild.ExtensibilityCleanTask" 


    <Target Name="GenuilderExtensibility">
            <Output TaskParameter="CompileOut"
    <Target Name="GenuilderExtensibilityClean">
            OutputPath="$(IntermediateOutputPath)" />

The implementation of this task has been kept as small as possible, because it was really hard to test. The core logic of Genuilder.Extensibility is in the GenEngine.

I'll explain some lines of the ExtensibilityTask.Execute method.

First GenEngine needs an IGenLogger to add logging capability to IExtension and GenItem. ExtensibilityTask just provides an implementation of this interface for MSBuild logging, the MsBuildLogger.

That's what we find in the implementation of ExtensibilityTask.

GenEngine engine = new GenEngine();
engine.Logger = new MSBuildLogger(this.Log);

Then GenEngine needs your extensions.


GetExtensions loads assemblies of every IExtension, and deserializes every extension. The problem is that these extensions were loaded in the Visual Studio process when compiling.

The implication is that when you try to debug an IExtension and recompile it, you got an error like this one:

Unable to copy file reference.dll to bin/reference.dll. 
  The process cannot access the file reference.dll because it is being used by another process

The fix is simple, I just need to load my ExtensibilityTask in a separate AppDomain, and unload it when the task is executed. That's why ExtensibilityTask inherits from AppDomainIsolatedTask instead of Task.

GenEngine.StartInfo.GenerationDirectory is the directory where new GenItems are generated.

engine.StartInfo.GenerationDirectory = OutputPath;

As you see in the Target file, this maps to IntermediateOutputDirectory. That is, by default, the "obj/Debug|Release" folder.

RunHistory is a file which keeps track of generated files after every GenEngine.Run, it keeps track of generated files and timestamp. Its goal is to see if files were modified between two runs so that GenEngine can set the value of GenItem.Modified before every run.

The other goal is to include the generated files of the last run to the list of GenEngine.SourceFiles before each run.


I worked hard to make the simplest design possible to implement Genuilder. And I'm happy to see there is not much lines of code.

I hope that Genuilder will make your projects a little more simple, and that its design is simple enough so that you don't need to know MSBuild to understand how Genuilder works.


This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


About the Author

Nicolas Dorier
Software Developer Freelance
France France
I am currently the CTO of Metaco, we are leveraging the Bitcoin Blockchain for delivering financial services.

I also developed a tool to make IaaS on Azure more easy to use IaaS Management Studio.

If you want to contact me, go this way Smile | :)

You may also be interested in...

Comments and Discussions

GeneralMy vote of 5 Pin
Kanasz Robert5-Nov-12 3:42
mvpKanasz Robert5-Nov-12 3:42 
GeneralRe: My vote of 5 Pin
Nicolas Dorier5-Nov-12 7:09
memberNicolas Dorier5-Nov-12 7:09 
Questionwhat are the requirements for installation? Pin
Southmountain26-Nov-11 12:24
memberSouthmountain26-Nov-11 12:24 
AnswerRe: what are the requirements for installation? Pin
Nicolas Dorier26-Nov-11 13:00
memberNicolas Dorier26-Nov-11 13:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.151125.3 | Last Updated 30 Nov 2011
Article Copyright 2011 by Nicolas Dorier
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid