Skip to main content

ItemGroup Gotcha

At work, we have been deploying the latest build from the build server to the test server manually for a while. I know this is not smart but the fact is, it really doesn’t take that much time to copy and paste files from build server to the test server.

Nevertheless, one day I was finally sick of this dumb process and decided to roll up my sleeves to make the build server do this monkey job automatically.  I wrote a MsBuild script, which automatically copies files to the test server from build server after finishing a build and the script below is the simplified version of it:

<PropertyGroup> 
  <Root>$(MSBuildProjectDirectory)</Root> 
  <SourceFolder>$(Root)\Source</SourceFolder> 
  <OutputFolder>$(Root)\Output</OutputFolder> 
  <DeployFolder>$(Root)\Deploy</DeployFolder> 
</PropertyGroup> 

<ItemGroup> 
  <DllFiles Include="$(OutputFolder)\*.dll" /> 
</ItemGroup> 

<Target Name="BuildAll"> 
  <Csc 
    Sources="$(SourceFolder)\MyClass1.cs" 
    TargetType="library" 
    OutputAssembly="$(OutputFolder)\MyClass1.dll" 
    EmitDebugInformation="True" /> 
  <Csc 
    Sources="$(SourceFolder)\MyClass2.cs" 
    TargetType="library" 
    OutputAssembly="$(OutputFolder)\MyClass2.dll" 
    EmitDebugInformation="True" /> 
</Target> 

<Target Name="DeployDlls" DependsOnTargets="BuildAll"> 
  <Copy 
    SourceFiles="@(DllFiles)" 
    DestinationFolder="$(DeployFolder)" /> 
</Target>

When the target DeployDlls is invoked with following command:

msbuild /t:DeployDlls build.proj

It is supposed to call the target BuildAll first due to the dependency, which builds the .cs files and then the DeployDlls target will run the Copy task to copy output files to the deploy folder. This seems to be a pretty straight forward script but it has a major bug in it. It does not work with a clean build.

The problem is that the ItemGroup clause is actually evaluated before any target was invoked. Therefore, when this script is executed against a clean build (i.e. no DLL files in the Build folder yet), the DllFiles item group will get evaluated into an empty array and therefore nothing will be copied at all after the build finished.

To fix this problem, the DeployDlls target must be updated to:

<Target Name="DeployDlls" DependsOnTargets="BuildAll">
  <CreateItem Include="$(OutputFolder)\*.dll">
    <Output
      TaskParameter="Include"
      ItemName="DllFiles"/>
  </CreateItem>
  <Copy
    SourceFiles="@(DllFiles)"
    DestinationFolder="$(DeployFolder)" />
</Target>

This way, the CreateItem task will populate DllFiles item group after the build is finished and right before the Copy task is executed.

Comments

Popular posts from this blog

Load Testing ASP.NET Sites with JMeter

Following my previous post about using JMeter to test MOSS, I tried to figure out what are the bare minimum requirements of using JMeter against a plain ASP.NET website. I wrote a very simple ASP.NET web application with just a button, a text fields and a static label. This application displays the content of a text file in the static label when it loads and write content of the text field back to the file when the button is clicked.I found all I need to do in order to script this using JMeter is to extract __VIEWSTATE and __EVENTVALIDATION fields then send them back in the update request. My JMeter test plain looks like this:

Load Testing SharePoint (MOSS) Sites with JMeter

I have used JMeter for load testing few non-ASP.NET web sites before, however I could not get it to work with ASP.NET web sites. This is mainly due to ASP.NET ViewState and event validations, which stops a recorded JMeter script from being played back.Recently I worked on a MOSS project and we were looking for tools to perform load testing on the server. Many people said the load testing tool in Microsoft Team System for Testers works well with MOSS. However, it is quite expensive so I decided to give JMeter another go. After several hours of hacking, I actually got it to work and here’s how I did it.My test page is the pretty standard MOSS edit document property screen with few extra text fields added and the goal here is to use a JMeter script to change the document properties. Once I have a working script, I can configure JMeter to fire hundreds of instances of this script simultaneously to simulate the user workload.As shown in the screenshot below, the test plan contains two HTTP…

COBOL Tutorial 00300 – Edited Fields

As I have mentioned in the last tutorial, you use edited fields in COBOL to format data fields into human-readable display strings. Let’s start with a numeric field:01 NUMERIC-FIELD PIC 999999V99.and some COBOL code that set and display the field value:MOVE 1234.5 TO NUMERIC-FIELD. DISPLAY NUMERIC-FIELD: ' NUMERIC-FIELD.As we’ve demonstrated in the previous tutorial, unused digits are padded with ugly zeros:NUMERIC-FIELD: 001234.50Let me put my C# programmer hat on again (apologies to Java, ruby, python, C/C++, assembly and many other programmers who don’t like C#), when we have to format a variable for display, we often use the string.Format method with a formatting string containing special formatting characters, which is “0,0.00” in the following example:// returns 1,234.50 string.Format("{0:0,0.00}", 1234.5)Now let’s come back to COBOL, an edited field is basically a normal COBOL data field with a formatting string in the picture clause instead of the “A”, “X” or “9”…