I have an odd issue with how msbuild is behaving with a VS2008 Web Deployment Project and would like to know why it seems to randomly misbehave.
I need to remove a number of files from a deployment folder that should only exist in my development environment. The files have been generated by the web application during dev/testing and are not included in my Visual Studio project/solution.
The configuration I am using is as follows:
<!-- Partial extract from Microsoft Visual Studio 2008 Web Deployment Project -->
<ItemGroup>
<DeleteAfterBuild Include="$(OutputPath)data\errors\*.xml" /> <!-- Folder 1: 36 files -->
<DeleteAfterBuild Include="$(OutputPath)data\logos\*.*" /> <!-- Folder 2: 2 files -->
<DeleteAfterBuild Include="$(OutputPath)banners\*.*" /> <!-- Folder 3: 1 file -->
</ItemGroup>
<Target Name="AfterBuild">
<Message Text="------ AfterBuild process starting ------" Importance="high" />
<Delete Files="@(DeleteAfterBuild)">
<Output TaskParameter="DeletedFiles" PropertyName="deleted" />
</Delete>
<Message Text="DELETED FILES: $(deleted)" Importance="high" />
<Message Text="------ AfterBuild process complete ------" Importance="high" />
</Target>
The problem I have is that when I do a build/rebuild of the Web Deployment Project it "sometimes" removes all the files but other times it will not remove anything! Or it will remove only one or two of the three folders in the DeleteAfterBuild item group. There seems to be no consistency in when the build process decides to remove the files or not.
When I've edited the configuration to include only Folder 1 (for example), it removes all the files correctly. Then adding Folder 2 and 3, it starts removing all the files as I want. Then, seeming at random times, I'll rebuild the project and it won't remove any of the files!
I have tried moving these items to the ExcludeFromBuild item group (which is probably where it should be) but it gives me the same unpredictable result.
Has anyone experienced this? Am I doing something wrong? Why does this happen?
The <ItemGroup>
is evaluated when the script loads and before the <Target>
has been processed.
There appears to be more than one way to do this correctly -
Include the <ItemGroup>
inside of the <Target>
and it should be evaluated at the correct time. This will work with MS-Build v3.5+
Use <CreateItem>
to generate the item list
Example build script for this -
<!-- Using ItemGroup -->
<Target Name="AfterBuild">
<ItemGroup>
<DeleteAfterBuild Include="$(OutputPath)data\errors\*.xml" />
</ItemGroup>
<Delete Files="@(DeleteAfterBuild)" />
</Target>
<!-- Using CreateItem -->
<Target Name="AfterBuild">
<CreateItem Include="$(OutputPath)data\errors\*.xml">
<Output TaskParameter="Include" ItemName="DeleteAfterBuild"/>
</CreateItem>
<Delete Files="@(DeleteAfterBuild)" />
</Target>
To explain why the delete process was generating 'unpredictable' results -
@(DeleteAfterBuild)
will evaluate with no files as the files don't exist in the $(OutputPath)
folder and will not delete any files as part of the AfterBuild
target@(DeleteAfterBuild)
will evaluate with all the expected files in the $(OutputPath)
folder and will remove the files as part of the AfterBuild
targetReference material: How To: Create Item Groups on the Fly, Delayed evaluation of items in MSBUILD file