Geeks With Blogs
Jennifer Zouak JENNIFER · ZOUAK's · BizTalk · and · .NET · column

I noticed the problem yesterday and spent the whole day on this. Some of this is documented, some not yet.

The problems: When building web applications with TFS's team build (we have 2005) the _PublishedWebsites directory does not contain some expected items: 1) Satellite Assemblies & their directories plus the wrong culture assembly is in the bin directory, 2) Assemblies which are needed as late-bound references may be missing, and 3) some normal assemblies also missing.

The solution:

1) Satellite assemblies. Due to a bug in the Web Application build targets file, these all end up being copied into the bin directory, without using subdirectories, so they overwrite each other and the last one to be compiled wins. Thus you may find your application unable to locate your neutral culture resources, but inexplicably be able to function fine in Portugese. The solution is available in this (obscure) thread posting, from which I will repeat the final solution below:

Update the following lines for the target "_CopyWebApplication".
    <Copy SourceFiles="@(IntermediateSatelliteAssembliesWithTargetPath)" DestinationFiles="@(IntermediateSatelliteAssembliesWithTargetPath->'$(WebProjectOutputDir)\bin\%(Culture)\$(TargetName).resources.dll')" SkipUnchangedFiles="true" />

    <Copy SourceFiles="@(ReferenceCopyLocalPaths)" DestinationFiles="@(ReferenceCopyLocalPaths->'$(WebProjectOutputDir)\bin\%(DestinationSubDirectory)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />

2) Loosely-Coupled (Late bound) Assemblies. You run into these types of DLL's with EntLib or Castle (Service Locator) or often when reflection is a part of the archtiecture.  They cause problems because you will need them in the bin directory at runtime, but the compiler cannot detect them.  (Before you start to feel clever, I am actually allergic to the GAC -- swell right up like a balloon -- so don't mention it, promise?) They are often left behind by tools (Setup projects, Unit Tests, MSBuild...).  The solution is simple -- add the reference to your user Interface or web service project (the runtime) and mark these items as "CopyLocal=true". But wait! They are automatically marked CopyLocal=true when you add them, aren't they? Well..... not actually. What you need to do is change the attribute to false and then back to true. Verify that this has been done by looking at your csproj files in notepad: references which are truly copyLocal have <Private>True</Private> for eachs uch reference.  This ensures that MSBuild/TFS will copy them to the output directory.

3) Random project assemblies were just missing. This was because I had marked it CopyLocal=false. Well this shouldn't be a surprise then, right? Except for the circum and instance that I have 36 projects and the one where it was marked CopyLocal=false was a unit test (so I wanted it to compile faster, so sue me). What I assume is going on is that in the assembly resolver cache each such assembly is only dealt with once. The first time it is compiled as a reference seems to be the one which determines the CopyLocal attribute.  The solution was to go over all csproj files and remove all instances of CopyLocal=false for my within-solution assemblies.  After this they began to appear in the published web sites. Yay!

Lesson of the day: Do not mark any assemblies as CopyLocal=false. This is a misguided attempt to avoid asking your boss for a RAM or HD upgrade. Face the music and get a better machine already. If you mark these items as false, just recognize that this is clearly not part of the test case at Microsoft...  and if you really want it to copy local, ensure the private xml tag is actually in the csproj files.

Final note on CSPROJ files -- any time you alter them, please please please remind your team not to automerge their changes or you will wonder why the next daily build doesn't show the results of your hard work.

 Credits: Thanks go to James Dawson's blog for pointing me in the right direction.

Finally: For reference, before I figured out all this, I implemented a heavy-handed workaround in the _CopyWebApplication target:

  <Message Text="Copying ReferencePath (DLL) (all of them!) " />
  <Copy SourceFiles="@(ReferencePath)" DestinationFolder="$(WebProjectOutputDir)\bin" SkipUnchangedFiles="false" />
  <Message Text="Copying ReferencePath (PDB) " />
   DestinationFolder="$(WebProjectOutputDir)\bin" SkipUnchangedFiles="false"
   Condition="Exists('%(RootDir)%(Directory)%(Filename).pdb')" /> 


Posted on Tuesday, November 17, 2009 5:59 PM | Back to top

Comments on this post: Team Build (Msbuild) & missing Loosely Coupled and Satellite Assemblies in published web directories

# re: Team Build (Msbuild) & missing Loosely Coupled and Satellite Assemblies in published web directories
Requesting Gravatar...
∆ ∆
Left by Klaus on Nov 02, 2010 10:01 AM

Your comment:
 (will show your gravatar)

Copyright © Jennifer Zouak | Powered by: