I Am Not Myself

Bills.Pay(Developer.Skills).ShouldBeTrue()

Target Overriding in MSBuild

Based on my last post, I have decided my course of action should be to attempt to override the _ResolveReferences target supplied to me by Web Deployment targets build file.

A quick Google search lead me to Jomo Fisher’s blog post titled "Hack the Build: Target Overriding Step-by-Step". A quick read through and I was ready to proceed.

First I opened the Microsoft.WebDeployment.targets file provided by they Web Deployment project. The default location of this file is C:\Program Files\MSBuild\Microsoft\WebDeployment\v8.0\. I copied the target xml for resolving references to the clipboard.

Next I opened my solution, right clicked on my web deployment project and selected Open Project File. This opens the MSBuild script file for the specific project I wish to override a target in. This is an important distinction because placing the override in the main TFSBuild.proj file is to late in the build process and will net you nothing.

I then pasted my new target into the project file near the end. My new target looks like this:

    <Target Name="_ResolveReferences"
            DependsOnTargets="_PrepareForBuild;GetFrameworkPathAndRedistList">
        <Message Text="Overriden in NAMESPACE.Service Web Deployment Project." />
        <CreateItem Include="$(_FullSourceWebDir)\Bin\*.refresh">
            <Output TaskParameter="Include" ItemName="References_RefreshFile" />
        </CreateItem>
        <ReadLinesFromFile File="%(References_RefreshFile.Identity)"
                           Condition=" '%(References_RefreshFile.Identity)' != '' ">
            <Output TaskParameter="Lines" ItemName="References_ReferenceRelPath" />
        </ReadLinesFromFile>
        <CombinePath BasePath="$(_FullSourceWebDir)" Paths="@(References_ReferenceRelPath)">
            <Output TaskParameter="CombinedPaths" ItemName="References" />
        </CombinePath>
        <Copy SourceFiles="@(References->'%(FullPath)')"
              DestinationFolder="$(_FullSourceWebDir)\Bin\"
              Condition="!Exists('%(References.Identity)')" ContinueOnError="true" />
        <ResolveAssemblyReference Assemblies="@(References->'%(FullPath)')"
                                  TargetFrameworkDirectories="$(TargetFrameworkDirectory)"
                                  InstalledAssemblyTables="@(InstalledAssemblyTables)"
                                  SearchPaths="{RawFileName};{TargetFrameworkDirectory};{GAC}"
                                  FindDependencies="true"
                                  FindSatellites="true"
                                  FindSerializationAssemblies="true"
                                  FindRelatedFiles="true"
                                  Condition="Exists('%(References.Identity)')">
            <Output TaskParameter="CopyLocalFiles" ItemName="References_CopyLocalFiles" />
        </ResolveAssemblyReference>
        <Copy SourceFiles="@(References_CopyLocalFiles)"
              DestinationFiles="@(References_CopyLocalFiles->'$(_FullSourceWebDir)\Bin\%(DestinationSubDirectory)%(Filename)%(Extension)')" />
    </Target>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Note that this is the exact logic from the web deployment targets file. I also added a message node to alert others to the fact that I have overridden this target and given the location of the override.

For this specific project the list of @(References) that is generated by this script incorrectly maps my two messaging libraries. I have *.refresh files for them, but they point to a common folder on the developers machine that does not exist on the build server. To remedy this I added the following code just after the call to CombinePath that generates the @(References) list and just prior to the Copy element:

<CreateItem Include="D:\Build\Build Common\Binaries\Release\Lib.*.dll">
  <Output TaskParameter="Include" ItemName="Messaging_Libraries"/>
</CreateItem>
<CreateItem Include="@(References);@(Messaging_Libraries)">
  <Output TaskParameter="Include" ItemName="NewReferences"/>
</CreateItem>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This allowed my build to successfully complete on the build server. Oddly enough, in the Build steps list the Compiling sources line item has a red X icon even though the compile had no problems. Trolling through the BuildLog I found that the Copy node was throwing errors that were converted to warnings, because the original list of references contains incorrect paths for the messaging DLLs and it fails to copy them.

The copy node seems to be redundant logically, so I commented it out and my build script is complete and working again.

Next on the agenda, getting Team Build to not download my entire source tree to build a single solution. As I add things to source control my build times are getting a bit crazy.

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

%d bloggers like this: