Friday, 8 July 2011

Working with MSBuild - <ItemGroup>

While working on MSBuild and doing some RND, I found that if we utilize <ItemGroup> properly we can achieve lot's things very easily and keep the build file very clean. I am not going in details but still trying to highlight how we can use it in various scenarios. You can utilize it then according to your requirement.


I assume you have created build file. If not then create build.xml (you can use naming convention as per your requirement). In my case I have created it "build.xml" at "C:\Projects\MSBuildDemo\", which contains some basic code as under. 


<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 
       <ItemGroup>
              <Department Include="Admin">
                     <Id>0001</Id>
                     <Name>Paul</Name>
       <Package>£45000</Package>
              </Department>
              <Department Include="HR">
                     <Id>0002</Id>
                     <Name>Ewen</Name>
      <Package>£51000</Package>
              </Department>
              <Department Include="Finance">
                     <Id>0003</Id>
                     <Name>Jacob</Name>
      <Package>£48000</Package>
              </Department>
              <Department Include="HR">
                     <Id>0004</Id>
                     <Name>Jacob</Name>
      <Package>£41000</Package>
              </Department>
       </ItemGroup>
 
</Project>
   

Note: Our example will be based on the </ItemGroup> which is added in it. 

Scenario 1: I want list of all departments in ItemGroup.


Add target as under in build file which will display list of all departments.


<Target Name="DepartmentsInItemGroup">
    <Message Text="***** Display department in ItemGroup  *****"/>

    <Message Text="@(Department)" />
</Target>

If you will open Visual Studio Command Prompt and execute the target "DepartmentsInItemGroup", you will see the result as under.


Notice here you will get "HR" department twice.

Scenario 2: I want list of unique departments in ItemGroup.

Same as above create target as below and execute it.




<Target Name="DepartmentList">
    <Message Text="***** List of Departments *****"/>

    <Message Text="%(Department.Identity)" />
</Target>


You will get the result as under having unique department.


Scenario 3: If you will see the <ItemGroup> above there are two person with the same name "Jacob". One is in Finance and other is in HR department. I want unique names from the <ItemGroup>.

Same as above create target as below and execute it.


<Target Name="UniqueEmployeeName">
    <Message Text="***** List of Unqiue Employee Names *****"/>

    <Message Text="%(Department.Name)"/>
</Target>

You will see the result as under.



If you will notice you will see names "Paul", "Ewen", "Jacob". There are two Jacob's but only one is displayed.


Scenario 4: I want Department based employee names list from the <ItemGroup>.

Create target as below and execute it.

<Target Name="DepartmentBasedEmployeeName">
    <Message Text="***** List of Department Based Employee Name *****"/>

    <Message Text="%(Department.Identity): @(Department->'%(Name)')" />
</Target>


You will see the result as under.


Scenario 5: I want to display same departments list for multiple authorized branches (Cross Join ItemGroups).


Create a property containing Authorized branches as under.



<PropertyGroup>
       <AuthorizedBranches>Branch1;Branch2;Branch3</AuthorizedBranches>
</PropertyGroup>

Create Target as under

<Target Name="DepartmentsInItemGroup">
    <Message Text="***** Display department in ItemGroup  *****"/>

       <ItemGroup>
              <AuthorizedBranch Include="$(AuthorizedBranches)"/>
       </ItemGroup>
      
    <Message Text="%(AuthorizedBranch.Identity)" />
       <Message Text=" "/>
      
       <CreateItem Include="@(Department)" AdditionalMetadata="BranchName=%(AuthorizedBranch.Identity)">
              <Output TaskParameter="Include" ItemName="BranchDetails"/>
       </CreateItem>

       <Message Text="Department : %(BranchDetails.Identity); AuthorsizedBranchName : %(BranchDetails.BranchName)" />
      
       <Message Text=" "/>
       <Message Text="Department : %(BranchDetails.Identity)"/>
      
  </Target>

You will see the Output as under.





Hope this will help to get started with <ItemGroup>. If you notice we have used different @, % with department itemgorup. So what that stands for?

@ is for an item in collection, which is a group of files with attached metadata under a name.

% denote an access to a metadata of an item.
There are wellknown metadatas (like RecursiveDir, see the definition in msdn) automatically attached to an item, or you can attach your own metadata when you define your items.
$ denotes access to a property.