A MSBuild convention proposal - Targets per assembly

MSBuild.aspx) is a very powerful build tool. Unfortunately, in my experience, I have seen it utilized very little. Instead, developers rely entirely on Visual Studio for the build, which is a mistake. I think there are a couple reasons for this:

  • Modifying the build feels like you are mucking in the internals of Visual Studio
  • There is no convention based approaches for how to handle custom bulid targets

Now, you could go the way of NAnt, and have complete independence from Visual Studio. I think this is a mistake as well. Visual Studio, while being a royal pain much of the time, is still a very very very powerful tool. I believe we should embrace it, while using MSBuild plus conventions to achieve ultimate flexibility.

The proposal

It’s actually quite simple. Each assembly/project already has its own *.csproj file, which is in essence a partial MSBuild file. The problem is editing it is weird and scary at times, because it is auto-generated by Visual Studio.

Just add the following to any or all your csproj files.

  ... All the visual studio muck ...
  <import project="$(MSBuildProjectName).targets" condition="Exists('$(MSBuildProjectName).targets')"></import>

Then add a file with that name. If your projects name is Reference.Web, then add a file named Reference.Web.targets and include it in the project. The content could contain something like the following.

<project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <files include="$(SolutionDir)\configuration\$(Configuration)\$(AssemblyName).*.config"></files>
    <files include="$(SolutionDir)\configuration\$(Configuration)\Common.*"></files>
  <target name="InstallConfiguration">    
    <copy sourcefiles="@(Files)" destinationfolder="$(OutputPath)"></copy>
  <target dependsontargets="InstallConfiguration" name="AfterBuild"></target>

Now you have a build file separate from the project that is really easy setup and use, straight for Visual Studio.

The only gotcha is Visual Studio won’t automatically notice the build file changes, so you still have to relad the assembly after you make a build file change.

UPDATE - More robust Import statement

Via @sayedihashimi

Even better would be a conditional import, and you should use the MSBuildProjectName property instead of AssemblyName.