Last week I posted up on how we had figured out a way of building .NET 2.0 code developed in Visual Studio 2008 under Team Build 2005 (a component of Team Foundation Server 2005). That post received quite a bit of traffic but like a lot of people I was disappointed that I couldn’t get build .NET 3.5 code, especially since some of our own internal users were asking questions about it.

This week I asked Grant Holliday to prepare a custom .NET 3.5 build server and plug it into Readify’s own TFS Now instance. My mission was clear – get our own internal .NET 3.5 projects building on top of the TFS Now infrastructure using Visual Studio 2008, Team Build 2005 and a cup of coffee.

Mission Accomplished!

I’m pleased to say that we managed to get to the bottom of this one with a fairly satisfactory solution. One of the things that I had to overcome was the fact that Team Build 2005 is hardwired to use the version of MSBuild that shipped with the .NET 2.0 runtime and unfortunately, Visual Studio 2008 projects that target the .NET 3.5 runtime must use the version of MSBuild that ships with the .NET 3.5 runtime.

As I was thinking about the problem I realized that since we already had a working .NET 2.0 build server, I would be able to dedicate this new build server to building .NET 3.5 code, so with a little bit of creative coding (and *.exe file replacement) I could make Team Build 2005 think it was calling MSBuild from .NET 2.0, but in reality, just forward that request to MSBuild from .NET 3.5.

What I needed to do was create a program called MSBuild.exe which I could drop in on top of the .NET 2.0 version of MSBuild that simply took the arguments passed to it and call the .NET 3.5 version of MSBuild. It ended up being about 25 lines of code in a single mainline.

image

After dropping the executable (MSBuild.exe) compiled from the code into the “C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727″ directory you will effectively be using .NET 3.5 to do all of your builds. My recommendation is to create a separate build server for this task so that you still have a clean .NET 2.0 build environment.

In the end this ended up being much simpler than I expected, and it seems to work perfecting, including updating the Team Foundation Server 2005 build store. If you have a build server you can use for this purpose you can avoid using the more involved Team Build trick that I posted about earlier.

When errors occur in applications developers use stack traces to to help them figure out where in the code something went wrong. The stack trace reports the the class and method from which an error originated, and depending on availability of debug symbols which line in the source file each of those class and methods up the call stack are associated.

Sometimes however it can be challenging to find the correct set of source files that were used to compile up the application.

Team Build helps by generating a unique build number whenever it produces a build, and placing all the build outputs into a specific drop folder, but it can be hard to trace back from a single DLL in production to the build number that it came from.

This is where build stamping comes in. Build stamping (not sure if this is what everyone calls it) is a technique where you embed some kind of identifier into the assembly metadata. A lot of people use a standard .NET version string (w.x.y.z) but I prefer to use the build number from Team Build (e.g. TrunkHelloWorld_20070830.5) and put it in something like the assembly description.

The purpose behind this post is to explain one possible way of performing this build stamping using Team Build, MSBuild and the MSBuild Community Tasks.

First, download and install the latest build of the MSBuild Community Tasks mentioned above. This set of libraries and custom build targets. Next you need to add the following code (Import element, and Target element) to the TFSBuild.proj file under the Team Build Type definition.

image

This will, then, during a build update all the AssemblyInfo.vb (or AssemblyInfo.cs if you change it accordingly) files under the solution root and replace the text “DeveloperUseOnly” in those files with the build number. All you need to do is put that text inside the metadata element where you want the information to appear and bingo – you are now stamping the builds with the Team Build build number.

I’d recommend putting it in the description because it shows up in the list of properties when you right mouse click the file in Windows Explorer.

A few weeks ago I was doing some work with a client in Sydney helping migrate their existing code base across to Team Foundation Server. One of the developers who also happens to play the build master/release manager role asked me if there was a better way of deploying their software.

Their current approach was copying the files onto a network share and adjusting the security policy of the user workstations to allow that code to execute with full trust. One of the problems that they were running into was that in order to update the program they had to rename all the files before deploying because they were locked by users who were currently using the software.

This was a fairly common approach back in the .NET 1.0/1.1 days, and if you wanted to get around it you had to build some kind of boot strapper that would set up an application domain and shadow copy the files, similar to the way that ASP.NET does to avoid file locking.

Fortunately, in a .NET 2.0+ world Microsoft has made our lives a little bit easier with the introduction of ClickOnce, although not everyone knows of its existence. I told the client about ClickOnce and they went off and did some experimentation.

The following week I visited the client again and I got the obvious question – how do we get ClickOnce working with Team Build?

The good news is that it isn’t that hard as Team Build has built-in support for working with ClickOnce enabled projects. The steps that you need to follow are:

  1. Enable ClickOnce in your application (you can do this via the properties window, or by doing step two below).
  2. Do one ClickOnce deployment manually to make sure all the appropriate configuration entries are written to the project file.
  3. Edit the TFSBuild.proj file and copy the “SolutionToBuild” line, and put it below, and rename it to “SolutionToPublish”. The screen show below provides an example. 

Sample from the configuration file.

Team Build will then build the code and place a versioned ClickOnce directory in the drop folder that you can then copy over to your deployment location. If you are feeling adventurous you could even use TFS Deployer to automate this step.

Update: We have now found a better way of doing this.

Last night whilst on the way to the airport Darren Neimke (our DevCentre manager and first customer of TFS Now) gave me a call to talk about an issue he was having with TFS Now (actually Team Foundation Server 2005 generally) and Visual Studio 2008. The good thing about using your own stuff is that you stumble across problems (hopefully) before your customers do which gives you a head-start getting them fixed or at least working around them.

One of the problems that Darren was having was getting a .NET 2.0 solution authored with Visual Studio 2008 to build successfully under Team Build 2005. Here is a screen shot of the build failure.

Failed Visual Studio 2008 build under Team Build 2005.

Even though the code being compiled targets the .NET 2.0 runtime the solution file itself has changed its format version and so MSBuild (from .NET 2.0) throws an error trying to process the file. To illustrate the (minor) difference between the Visual Studio 2005 and Visual Studio 2008 solution file formats, here are two screen shots.

First a Visual Studio 2005 solution file header:

Sample Visual Studio 2005 solution file.

Second a Visual Studio 2008 solution file header:

Sample Visual Studio 2008 solution file.

Notice that the Format Version value has been changed from “9.0″ to “10.0″. I’m sure that there are some interesting stories about why these numbers are nine and ten respectively since Visual Studio 2005 is actually Visual Studio 8.0, and Visual Studio 2008 is actually Visual Studio 9.0 – but anyway, I digress.

In a nutshell, the problem is that the version of MSBuild that Team Build 2005 integrates with gets to a solution file with Format Version 10.0 and simply falls over with the following error:

Build FAILED.
C:\Builds\TFSNow\TfsNow-PublicWebsite-Continuous\Sources\PublicWebsite.sln(2): Solution file error MSB5014: File format version is not recognized.  MSBuild can only read solution files between versions 7.0 and 9.0, inclusive.

The reason we get any sort of output at all from Team Build is due to the fact that the first build file that it actually processes is the TFSBuild.proj file located at $/[TeamProject]/TeamBuildTypes/[BuildType]/TFSBuild.proj.

In order to work around this problem we need to get creative. Because TFSBuild.proj actually starts getting processed we actually have an opportunity to inject some pre-processing logic to “fix” up the PublicWebsite.sln file. At the command prompt I tested the following PowerShell pipeline that transformed the solution file:

get-content PublicWebsite.sln | % { $_.Replace(”Format Version 10.0″, “Format Version 9.0″) } | set-content PublicWebsite.Fixed.sln

This one is pretty simple. It pipes each line from the solution file through a little replacement routine and spits it back out into a new file. If I tell MSBuild to build this file it won’t blow up straight away but it will still fail. The problem is that the <Import /> elements in all of the *.csproj MSBuild files are looking for an updated set of *.targets files for Visual Studio 2008.

Rather than install Visual Studio 2008 on our build server I thought it might be easier to just copy the directory:

C:\Program Files\MSBuild\Microsoft\VisualStudio\v8.0

To:

C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0

This is a fairly major hack but when I triggered MSBuild on the “fixed” solution file it seemed to pay off (only a few warnings about quality tool references). The next step is to get this all working under Team Build so that the solution file is dynamically fixed and Darren can continue developing with Visual Studio 2008.

Since I used PowerShell, I needed a MSBuild task that would allow me to invoke a piece of PowerShell code from within an MSBuild script. I found this great implementation of just such a task on Arild Fines’ blog. Because Arild developed his task before PowerShell shipped, when you download the zip file with the binary, you will need to recompile the code, this worked first time for me – no modifications required.

Once that is done upload the PowershellMSBuildTask.dll file into the same location in version control as TFSBuild.proj build file and modify said file by adding the following XML:

Modified TFSBuild.proj file.

You will also need to update the SolutionToBuild item group to point at the “fixed” solution file. Once all this in place you should be able to build Visual Studio 2008 solution files targeting the .NET 2.0 Framework via Team Build. I’m still looking at ways that Team Foundation Server 2005 users can stagger their adoption of Visual Studio 2008 by building .NET 3.5 projects on Team Build 2005, if I come up with a workable solution I will post it here. As proof that all this works, here is a screen shot of the successful build.

image

Finally, I have a few thoughts about the whole Visual Studio 2008/Team Foundation Server 2008 migration pain that people are about to go through. First of all it would have been nice if Microsoft could have shipped an updated Team Build 2005 build server (Team Build 2005 R2 anybody?) which could handle kicking off builds with a version of MSBuild that can support .NET 3.5 projects.

Visual Studio 2008 adoption is probably going to lead Team Foundation Server 2008 adoption in most organizations as I can’t see many companies opting to upgrade a working Team Foundation Server 2005 installation to Team Foundation Server 2008 even with a Go Live license in place. Without a half-way point a lot of organizations might hold off starting Visual Studio 2008-based projects until Team Foundation Server 2008 actually ships and they can move all of their code forward.

QVSTSUG Logo Just a quick note to say that I will be presenting at two users groups in Brisbane over the next week or so. The first group that I will be presenting at is the Queensland VSTS User Group run by Anthony Borton. In this session I’ll be presenting on TFS Integrator and TFS Deployer, both of which are tools developed by Chris Burrows from Readify.

So why am I posting this on the TFS Now blog? Well TFS Integrator is actually pre-installed on TFS Now instances and is ready to use. Depending on what connectivity is like up on the stage I may end up using the Readify TFS Now instance to demonstrate how the tools work. You can find out all the details about this session on the cool WSS site that Anthony has set up.

The other presentation that I am giving is at the Queensland MSDN User Group which I have posted about over on my personal blog.

When organizations adopt TFS Now (or indeed TFS itself) they get access to Team Build. Team Build is a distributed “build engine” that allows build masters to request that a build be performed on a remote machine that has the Team Build agent installed on it. When we pulled together the TFS Now SaaS offering we were very keen on enabling the use of Team Build.

When you get a TFS Now account provisioned we automatically set you up with a build server which is capable of building both .NET 2.0 and .NET 3.0 code-bases. When you kick off a build this build server is made available to you.

Custom Build Servers?

For more complex build scenarios you can also setup your own Team Build server which your hosted TFS instance can connect to across the Internet. This is useful if you have special dependencies that we can’t (currently) replicate in our hosted environment.

Having said that I am interested in hearing from you if you do have custom build server requirements because we want to enable this scenario in the not to distant future and understanding your requirements would help us greatly.

Continuous Integration Support

A little while ago Readify developed a tool called TFS Integrator. TFS Integrator plugs a hole in the Team Foundation Server 1.0 feature set where Continuous Integration wasn’t built into the product. When customers provision a TFS Now instance we automatically enable the use of TFS Integrator. This is really useful for multi-person development teams who need to make sure that the code that they are adding to the repository is generally stable – at least from a build point of view.

MSBuild Help?

Once you are up and running with TFS Now you are probably going to need to spend a little bit of time getting your build sorted out. To do this you will need to become familiar with MSBuild. MSBuild is the build scripting language that Team Build calls out to when it wants to build one of your solution files. I recommend that you check out the following resources when skilling up on MSBuild.

People are starting to realize that there is now a hosted Team Foundation Server solution on the market with the launch of TFS Now this week. Jonathan Allen posted an article on his blog(?) pondering the need for a hosted offering.

I guess from a business perspective we would like to think that there is a market for hosted TFS, and before launching the service we certainly did research into the kinds of customers that are likely the leverage the offering at its current price point.

Over time I am confident that TFS will becoming a better multi-tenant system which will help drive down costs. Believe it or not we actually want this offering to be as cheap as possible to help drive adoption and we are going to be actively giving Microsoft feedback on our current pain points so that feedback can be integrated into future versions of Team Foundation Server.

It has been a pretty exciting week for TFS Now. First we got lots of link love from bloggers around the world (thanks guys), then, we received a number of sign-up requests for the service.

Since people are adopting the service it is probably a good time to talk about source code migration strategies as they apply to TFS Now (and TFS generally). Andrew Matthews started a thread on our internal mailing list so that we could discuss it:

“We have the XYZ repository now. It’s flaky as hell. How can we extract all of our history out of it into TFS Now, and how long will it take?”

The quick answer is that out of the box Microsoft ships a converter that allows you to migrate from your existing Visual SourceSafe database. In order to get this working with TFS Now you will probably need to build a workstation and join it to your dedicated TFS Now domain. This will avoid any potential authentication issues.

If you need to convert from other version control systems I am interested in hearing from you. There are various options available ranging from possibly setting up CS-Coverter from ComponentSoftware Inc., or even writing custom tools for the TFS Migration and Synchronization Toolkit.

One of the things you will notice when you migrate the code is that the changes are applied from the time you do the migration. So it won’t put the dates from the source repository in the destination repository (other than for reference purposes in the comments).

Right now I am not sure how it will take to do it across the Internet, but before you start you might want to drop us a line so that we can take a check point on your installation and suspend maintenance activities during the migration.

Thanks to Tatham Oddie we now know about a CSS/image roll over issue on the TFS Now homepage. I’m actually sitting at a hotel having breakfast right now and I didn’t want to let the suggestion that Tatham made fall through the cracks – so I’ve logged a bug (work item 692 in our work item store for those who are counting).

Bug692

Looking at Tatham’s solution I’m a little bit concerned about how some browsers might handle moving the image, and in the end, as Tatham says it may not be worth fixing. I’ve added the bug anyway and it can get prioritized using the normal process.

Thanks Tatham!

Footnote: The observant amongst you will notice that I am actually using Visual Studio 2008 to log this bug!

Grant Holliday who runs the Canberra VSTS User Group has managed to get around to putting up the user group web-site. I’ve added a link to the UG site to the links bar on this blog.