MSBuild 4.0 BeforeTargets and AfterTargets


Visual Studio 2010 Beta 1 gives the wider community their first look at what is on offer in MSBuild 4.0. In this post I’ll briefly cover the new BeforeTargets and AfterTargets features.

These targets sit in the new MSBuild.Construction namespace and on initial inspection, they provide you with the ability to plug in targets to alter the execution path of a MSBuild file.

Lets cover this with a basic example. Running the following sample,

<Project xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>

  <Target Name=”Default”>
    <Message Text=”Hello from Default”/>
  </Target>

</Project>

we get the expected:

Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” on node 1 (default targets).
  Hello from Default
Done Building Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” (default targets).

Now suppose you wanted to run a target before the Default target. In .NET 3.5 you would use DependsOnTargets as shown with the following:

<Project xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>

  <Target Name=”Default” DependsOnTargets=”DefaultDependsOn”>
    <Message Text=”Hello from Default”/>
  </Target>

  <Target Name=”DefaultDependsOn”>
    <Message Text=”Hello from DefaultDependsOn”/>
  </Target>

</Project>

which would result in:

Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” on node 1 (default targets).
  Hello from DefaultDependsOn
Default:
Hello from Default
Done Building Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” (default targets).

So what’s wrong with DependsOnTargets? Well, not a lot, however the above implementation does create an explicit bind between the targets and may reduce your ability to reuse the default target efficiently.

Enter BeforeTargets

In MSBuild 4.0 you can achieve the same result by using the following

<Project xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>

  <Target Name=”Default”>
    <Message Text=”Hello from Default”/>
  </Target>

  <Target Name=”DefaultBeforeTarget” BeforeTargets=”Default”>
    <Message Text=”Hello from DefaultBeforeTarget”/>
  </Target>

</Project>

which results in:

Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” on node 1 (default targets).
Hello from DefaultBeforeTarget
Default:
Hello from Default
Done Building Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” (default targets).

So we get the same functionality, but our targets are arguably more reusable. I don’t think there is a need to go and re-write all your code, but remember that you have this feature in your tool belt in 4.0.

Now it may be that I’ve used it a lot, but DependsOnTargets makes a lot of sense to me. It does ‘as it reads’, i.e. the Default target depends on Targets xyz… A minor concern I have with this new feature is that it doesn’t do ‘as it reads’. The first time i saw a sample with this I expected that all the BeforeTargets would run before the named target. Perhaps a better name would be RunBeforeTargets, which makes it clear that the named target will run before all the targets listed. The same logic could be applied to AfterTargets (or perhaps a better named RunAfterTargets)

Enter AfterTargets

In a very similar light, the new AfterTargets feature allows us to run a target after a given target. Running the following sample:

<Project xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>

  <Target Name=”Default”>
    <Message Text=”Hello from Default”/>
  </Target>

  <Target Name=”DefaultBeforeTarget” BeforeTargets=”Default”>
    <Message Text=”Hello from DefaultBeforeTarget”/>
  </Target>

  <Target Name=”DefaultAfterTarget” AfterTargets=”Default”>
    <Message Text=”Hello from DefaultAfterTarget”/>
  </Target>
</Project>

we get:

Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” on node 1 (default targets).
  Hello from DefaultBeforeTarget
Default:
  Hello from Default
DefaultAfterTarget:
  Hello from DefaultAfterTarget
Done Building Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” (default targets).

But DependsonTargets Rules!

So you can see how these two new features provide the ability to easily tweak execution. You can also plug into existing target frameworks without affecting other users. Now what of the DependsOnTargets in 4.0? It still lives on of course and its important to understand the order of execution.

Take the following example:

<Project xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>

  <Target Name=”Default” DependsOnTargets=”DefaultDependsOn”>
    <Message Text=”Hello from Default”/>
  </Target>

  <Target Name=”DefaultDependsOn”>
    <Message Text=”Hello from DefaultDependsOn”/>
  </Target>

  <Target Name=”DefaultBeforeTarget” BeforeTargets=”Default”>
    <Message Text=”Hello from DefaultBeforeTarget”/>
  </Target>

  <Target Name=”DefaultAfterTarget” AfterTargets=”Default”>
    <Message Text=”Hello from DefaultAfterTarget”/>
  </Target>
</Project>

Would you expect to see DefaultBeforeTarget or DefaultDependsOn execute first? Below is the result:

Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” on node 1 (default targets).
  Hello from DefaultDependsOn
DefaultBeforeTarget:
  Hello from DefaultBeforeTarget
Default:
  Hello from Default
DefaultAfterTarget:
  Hello from DefaultAfterTarget
Done Building Project “C:\Users\administrator.DEV\Desktop\MSBuild Samples\BeforeAfter.proj” (default targets).

So as you can see, order of execution is DependsOnTargets, BeforeTargets, [NamedTarget], AfterTargets.

What do you think of this new feature? Can you think of better names or do they make sense to you?

— Mike

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s