I want to be able to perform additional actions when building a Visual Studio 2010 Project. Out of the box there is the option of adding pre or post-build events. However, depending on what you want to do, this may cause issues when using Team Build in Team Foundation Server 2010. So another option might be to customise the Team Build. But what if you want to do these additional actions locally and in Team Build? Well I have a solution that is working well for me.
There are four steps:
- Learn all you can about MSBuild, see http://msdn.microsoft.com/en-us/library/dd393574.aspx
- Decide which MSBuild target(s) to override. You should be really careful not to select a target that does some existing work, awful things could happen to your build if you do. There are however, a number of 'empty' targets to choose from, that have been deliberately left for you and me to override as we please. For example 'BeforeBuild' and 'AfterBuild'.
- Write a file that contains the targets you want to override. I tend to either add a .targets files to my Solution (that way its under source control and available to every project in the Solution) or put it in a central location, so its available to every Solution.
- Alter the Project's .csproj file to import the new targets file. This will cause the targets to be run every time you build the Project locally or with Team Build.
Assuming you've done step 1 and you are now an MSBuild expert, lets move onto Step 2. Deciding which target to override.
- Do you need to do something before compilation? Say, alter values in app.config, then choose 'BeforeBuild'.
- What about copying dlls into a specific location? Then choose 'AfterBuild'.
Step 3, writing a .targets file.
- First add an xml file to the Visual Studio Solution that contains the Projects you want to affect. So right-click the Solution and select Add-> New Item…, choose XML File, and save it with a .targets extension instead of .xml. For example, MyBuild.targets.
- You will need to add a Project element using the MSBuild namespace and inside that you may need to add some UsingTask elements.
- Following any UsingTask elements, add your Targets. Here is an example of a very simple .targets file, that just writes a message to the Output Window during the Build:
<?xml version="1.0" encoding="utf-8"?>
<Message Text="Running BeforeBuild Target" Importance="high"/>
Step 4, altering a Project's .csproj file.
- To tell MSBuild that we want to run the new Target, we have to put an Import element inside a Project's .csproj file.
- To do this manually, first check out the .csproj file from source control. If you are using Team Foundation Server, open the Source Control pane from Team Explorer. Then navigate to the .csproj file and check it out.
- Open Windows Explorer and find the .csproj file, then right-click and open with Notepad.
- Scroll right down to the bottom of the .csproj file, and just before the closing Project tag, add an Import tag, so it looks like this:
<Import Project="..\MyBuild.targets" />
- You will notice I've used a relative path, because I saved my .targets file as a Solution File. You could of course, put the .targets file anywhere you want, in which case use an appropriate path.
- Close and save the .csproj file. If the project was open in Visual Studio, then you will be prompted to reload the Project. If you've made a mistake with the syntax, the reload will fail. Just go back and manually edit the .csproj file to fix it.
So that's it. To check this has worked, rebuild your Solution. Because there is a Message in the example Target, this message will appear in the Output window just after line that says the Build is starting for the Project, like this:
------ Build started: Project: ClassLibrary1, Configuration: Debug Any CPU ------
Running BeforeBuild Target
ClassLibrary1 -> D:\Projects\MySolution\ClassLibrary1\bin\Debug\ClassLibrary1.dll
In my next post I'll talk about a way to add the Import tag to the .csproj file from within Visual Studio 2010 itself by adding a macro to the Project's Context Menu.
Jul 12 2011, 01:47 PM
Now, I realise that those of you who use blog comments such as these to
spread your worthless spam are not the cleverest people on the face of the planet.
So, I thought I'd make it clear that you're wasting your time posting your pointless
garbage here. Quite simply, it will never be published. Thankfully, unlike yourselves,
I'm blessed with an inherent ability to identify irrelevant content and it's every bit
as easy for me to toss your contribution into the virtual waste bin as it is to publish it.
So, guess what? Unless your comments are relevant (and I mean, really relevant, not
some thinly veiled attempt to get me to link to your site) they're never going to appear
on here. So, they're never go to appear in a search engine, never going to boost your
customer's Google page rank and never going to achieve anything in terms of Search
Engine Optimisation. Please, practice being a parasite elsewhere. Oh, and I'm confident
that my genuine readers are perfectly well endowed and enjoy a full and healthy lifestyle
without help from you. Thanks for reading.