Oct 012011
 

The Windows Workflow Foundation (WF) build process templates are powerful but before long you’ll probably want to do something that is impossible or impractical to achieve with a pure WF solution. That’s where custom build activities come in.

Custom build activities are .NET classes which inherit from System.Activities.CodeActivity (or one of a few other classes).

To get started, you need to create a Visual Studio solution including two projects – one for the custom activities and one for your process template(s). I started with Ewald Hofman’s great tutorial and solution download here. There are also detailed instructions in the excellent Rangers Build Customisation Guide (which, incidentally, I found to be much better on TFS Build than Inside the Microsoft Build Engine – the only book currently available on the topic).

After downloading Ewald’s solution I made a couple of tweaks. First, I removed the post-build event which copies the compiled assembly and debugging symbols files (.dll and .pdb) to the source location where the Build Controller looks for custom assemblies. I did that because whenever new or updated assemblies are dropped into that location the Build Controller restarts, killing any running builds and upsetting your team! You can create equivalent actions in a batch file, which gives better control than a post-build event. The only downside is that you have to remember to run it. Here’s an example:

REM Checkout the dll and the pdb file
"C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe" checkout "../BuildCustomActivities/BuildTasks.dll"
"C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe" checkout "../BuildCustomActivities/BuildTasks.pdb"

REM Copy the dll and the pdb file to the source control location
xcopy /y "BuildTasks\bin\Debug\BuildTasks.dll" "..\BuildCustomActivities"
xcopy /y "BuildTasks\bin\Debug\BuildTasks.pdb" "..\BuildCustomActivities"

REM Checkin the dll and the pdb file
"C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe" checkin "../BuildCustomActivities/BuildTasks.dll" /comment:"Auto check-in by batch script"
"C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe" checkin "../BuildCustomActivities/BuildTasks.pdb" /comment:"Auto check-in by batch script"

Secondly, I didn’t like that a couple of custom activities required the BuildDetail object to be passed to them as an argument – the built in context object gives you access to that so there’s no need to pass it in. To make that change (if you want to – it’s not absolutely necessary) remove this bit from the code:

[RequiredArgument]
public InArgument<IBuildDetail> BuildDetail { get; set; }

Then replace this:

IBuildDetail buildDetail = context.GetValue(this.BuildDetail);

With this:

IBuildDetail buildDetail = context.GetExtension<IBuildDetail>;();

The next thing I did was add my customised process template (which started as a copy of DefaultTemplate.xaml) to the Templates project as a linked item. When I did that and built the solution I got lots of “TfsBuild.Process already contains a definition for…” errors like:

This is because the new process template has the same namespace and class name as the existing template in the project. Why is this a problem? Well, a WF .xaml file represents a class and the template project compiles to a .NET assembly, a fact that is easy to miss because you don’t normally inspect the underlying XML, and for TFS Build you only need the .xaml files – not the built assembly. The quickest way to resolve this error is to change the namespace alone, as it’s only in two locations. First, open the .xaml file and find this (it should be in line 1):

x:Class="TfsBuild.Process"

And change the namespace, for example to:

x:Class="MyCustomTfsBuild.Process"

Then find:

xmlns:this="clr-namespace:TfsBuild;"

And replace with your new namespace, like:

xmlns:this="clr-namespace:MyCustomTfsBuild;"

If you would rather change the class name that works fine too. Change the first snippet shown above (x:Class…) to TfsBuild.MyCustomProcess then every instance of <this:Process… to <this:MyCustomProcess…

Tip: If you get a “mapping URI not valid” error when building the solution after adding a new template, try excluding the template from the project then adding it back again – it worked for me.

You shouldn’t have to do anything special to get the custom activities in the Visual Studio toolbox – as long as you have the solution open when working on the template.

You can use activities from Ewald Hofman’s sample solution, write your own, or check out the vast selection in the Community TFS Build Extensions.

  One Response to “Custom Build Activities in TFS 2010”

  1. […] (assuming you have set up a solution for creating custom build activities) you need to create an activity which gets the label we will pass in via the LastLabel argument. […]

Sorry, the comment form is closed at this time.