How To: Distribute Your Custom Task and .Targets file

We’ve had variations of the same question on how to distribute tasks come through both internal and external channels in the last couple of weeks. Here’s one example:

If we have a product that is installing custom MSBuild tasks, are there any type of guidelines on where they should be installed, do they need to be registered, etc.?

The good news is you don’t have to register anything at all. You just need to figure out what the best directory is to install your goo. Typically there’s two pieces of goo that need to be installed: the assembly with the task(s) in it, and the .targets file that includes a <UsingTask>, assorted properties, and perhaps even a target override.

It turns out that you’ll probably want your installer to offer the user the choice of two installation points: one for installing your new MSBuild magic on a developer’s machine, and another for installing it in some sort of build-lab environment. Here’s a little table with the suggested installation locations:

Developer Machine Build Lab
Assembly Global Assembly Cache Location of user’s choosing
.Targets File $(MSBuildExtensionsPath) Location of user’s choosing

This requires your setup to actually have two different .targets files, since the <UsingTask> will be different depending on where the task assembly is installed.

To see all this in action I suggest downloading the AssemblyInfoTask sources. It includes a setup project that gives the user of installing the assembly into either the GAC or to their local application data folder. This could be extended to allow installation to GAC or a folder of the user’s choosing.

[ Author: Neil Enns ]

Comments (3)

  1. Morten says:

    Great post!

    I looked at the Setup for the mentioned AssemblyInfoTask plugin. When choosing "Install to users app data folder" I can’t understand  that the targets file also gets installed in the users appdata folder. Shouldn’t it always get installed under the $(MSBuildExtensionsPath) folder. In the importing project file the <Import> should be invariant to the installation method. The important aspect of the targets file is not where it is installed, but which of the two targets files are installed (the one that triggers a LoadFrom=AssemblyFile attribute on the UsingTask element, or the one that triggers a Load=Assembly attribute on the UsingTask element)

    Am I missing something here?

  2. I’m going to stop writing new tasks for a couple of entries while I take some time to clean things up.

Skip to main content