Lessons in TFS Build - BuildShadowTask Failed

   Submit to Reddit      
  

Recently I have been testing out the private accessor mechanism in .NET to test private methods. I know there is a large debate over whether private methods should be tested directly or whether they should only be tested via public methods. But, this post is not about whether to test private methods or not.

In this particular application, there are a large number of Visual Studio projects, so File References are used everywhere instead of Project References so that the solution file is as small as possible, containing only the projects that are under development.

I recently modified the TFS build definition to run the tests as part of the TFS build, and then the build failed with the following log information.

Using "BuildShadowTask" task from assembly "C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.VisualStudio.TestTools.BuildShadowsTask.dll".

Task "BuildShadowTask"

C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.TeamTest.targets(18,5): error : Could not load file or assembly '[A.File.Referenced.Assembly.Name.Here], Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

Done executing task "BuildShadowTask" -- FAILED.

Done building target "ResolveTestReferences" in project "[My.Test.Project.Name.Here.csproj]" -- FAILED.

When using the accessor mechanism to test private methods in a .NET language, the TFS build target "ResolveTestReferences" is called as part of the TFS Build process to build the xyz_Accessor.dll. [This build target resides in "C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.TeamTest.Targets".]

It appears that in order for this build target to be successful, the test project must contain:

  • At least one Project Reference (as opposed to a File Reference); and
  • Copy Local set to True on the reference to the assembly for which the Accessor will be created.

In order to work around the first problem, I created a blank Visual Studio project that I called "AccessorFix" which I include in my test solution. I then added a Project Reference from each test project that uses accessors to the AccessorFix project.

Now the TFS build of the shadow accessors completes successfully! Go figure.

Lessons In .NET - Assembly Binding Configuration

   Submit to Reddit      
  

The Microsoft .NET Framework 2.0 SDK Configuration tool is a GUI for the C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config file.

However, I was working on a machine that didn't have the SDK installed and I didn't want to install it on that machine. I needed to redirect an assembly by adding an <assemblyBinding> element, so I looked up the specification of the element at http://msdn.microsoft.com/en-us/library/twy1dw1e.aspx and went directly to the machine.config file in a text editor tool.

Regarding the appliesTo attribute, the documentation says the following:

... If no appliesTo attribute is specified, the <assemblyBinding> element applies to all versions of the .NET Framework.

I wanted my binding to apply to all the versions of the .NET framework, and I thought I would specify that in the XML by specifying appliesTo="", as below.

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" appliesTo="">
    ...
</assemblyBinding>

In all applications that I am familiar with - and even in ASP.NET - an attribute that has a value of the empty string behaves like the attribute has not been specified.

However, if you manually add an assembly binding section, do NOT specify appliesTo="", because that will actually prevent the assembly bindings applying to any .NET version at all!

Even after installing and using the tool to remove/fix the inner details of all assembly bindings, the actual <assemblyBinding> element was not removed and the manually added appliesTo="" remained - and this would cause future havoc.

Moral of the story: do NOT specify appliesTo="" in an assemblyBinding element!!

Lessons In MSBuild - Introduction

   Submit to Reddit      
  

The Microsoft build engine (MSBuild) is not necessarily the easiest to learn, and documentation and examples can be difficult to find.

There is however an excellent book written by Sayed Ibrahim Hashimi and William Bartholomew titled "Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build" (Microsoft Press, 2009, ISBN-13: 978-0-7356-2628-7). I very strongly recommend purchasing this book if you are serious about learning MSBuild.

In this series of lessons I will be discussing a few MSBuild related tips that I found useful to understand during my recent dabbling in MSBuild 3.5 projects.

Lessons in PowerShell - Looping Through File Folders

   Submit to Reddit      
  

One way in PowerShell to get a collection of file folders is by using the .NET System.IO.Directory.GetDirectories function. Time is short, and I am familiar with that, so I will use the .NET library in this example script.

Here is one way in which it can be done.

$folders=[System.IO.Directory]::GetDirectories("c:\xxxx")

foreach ($folderName in $folders)
{                
    ...
}

If we wanted to, within the loop we could instantiate a System.IO.DirectoryInfo object to give us more information about the folder.

$folder = New-Object System.IO.DirectoryInfo($folderName)

And then we can access the properties on that class, like the folder's LastWriteTime in order to find out how old it is.

Here is a complete script.

$now = Get-Date
$yesterday = $now.AddDays(-1)
$folders=[System.IO.Directory]::GetDirectories("c:\program files")                    

foreach ($folderName in $folders)                    
{
    $folder = New-Object System.IO.DirectoryInfo($folderName)

    if ($folder.LastWriteTime -lt $yesterday)                    
    {                     
        Write-Host("Folder " + $folderName + " is at least a day old")                    
    }
    else
    {
        Write-Host("Folder " + $folderName + " is less than a day old")
    }                    
}