Wednesday, August 04, 2010

Recently there was a question on an internal mailing list asking the question can you tell the difference between

<ItemGroup>
  <Content Include="Sample-DefinedEmpty.sdf">
    <SubPath></SubPath>
  </Content>
</ItemGroup>

and

<ItemGroup>
  <Content Include="Sample-NotDefined.sdf">
  </Content>
</ItemGroup>

You cannot detect this out of the box, but you can by creating a custom task. Better would be to create an inline task so that you don’t have to deal with the headache of maintaining a .dll for something like this, unless you are using it on many different project files. Basically the task that we will create will need two parameters; the Item itself (single value) and MetadataName (metadata name to check for). It will have one output parameter, MetadataDefined, which we can check to see if the metadata value was defined or not.

This is a pretty easy task to create because we just look at the MetadataNames property on the ITaskItem interface. The task as well as a sample target is shown below.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  
  <UsingTask TaskFactory="CodeTaskFactory"
             TaskName="MetadataExists"
             AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <MetadataName Required="true"/>
      <Item ParameterType="Microsoft.Build.Framework.ITaskItem"/>
      <MetadataDefined ParameterType="System.Boolean" Output="true" />      
    </ParameterGroup>
    <Task>
      <Code>
        <![CDATA[
            this.MetadataDefined = false;
            if (this.Item != null)
            {
                foreach (string name in this.Item.MetadataNames)
                {
                    if (string.Compare(this.MetadataName, name, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        this.MetadataDefined = true;
                        break;
                    }
                }
            }          
        ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="CheckForMetadata">

<ItemGroup>
  <Content Include="Sample-DefinedEmpty.sdf">
    <SubPath></SubPath>
  </Content>
  <Content Include="Sample-NotDefined.sdf">
  </Content>
</ItemGroup>

    <Message Text="Starting - Content"/>

    <!-- Create an Item which has exactly 1 value to pass to the task -->
    <ItemGroup>
      <_Content Remove="@(_Content)"/>
      <_Content Include="@(Content)" Condition=" '%(Content.Identity)' == 'Sample-DefinedEmpty.sdf' "/>
    </ItemGroup>
    <MetadataExists MetadataName="SubPath" Item="@(_Content)">
      <Output PropertyName="existsResult" TaskParameter="MetadataDefined"/>
    </MetadataExists>

    <Message Text="existsResult: $(existsResult)" />


    <Message Text="Starting - Content2"/>
    <!-- Create an Item which has exactly 1 value to pass to the task -->
    <ItemGroup>
      <_Content Remove="@(_Content)"/>
      <_Content Include="@(Content)" Condition=" '%(Content.Identity)' == 'Sample-NotDefined.sdf' "/>
    </ItemGroup>
    <MetadataExists MetadataName="SubPath" Item="@(_Content)">
      <Output PropertyName="existsResult" TaskParameter="MetadataDefined"/>
    </MetadataExists>

    <Message Text="existsResult: $(existsResult)" />
  </Target>
</Project>

Here you can take a look at the MetadataExists task and its usage. The only thing that really needs to be pointed out here is that since this task accepts a single item value we will have to take the item group Content and pick from it a specific value which is passed to the task. That is what I am doing when I create the temp item _Content. If you execute the CheckForMetadata target with the command msbuild CheckMetadata01.proj /t:CheckForMetadata the result will be what is shown below.

CheckMetadata

So from the output you can see that we were able to tell the difference!

BTW, if you were wondering if you can do the same with properties, the answer is no.

Sayed Ibrahim Hashimi

Wednesday, August 04, 2010 7:17:20 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1]  | 
Wednesday, November 23, 2011 5:45:01 AM (GMT Standard Time, UTC+00:00)
very good post
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, strike, strong, sub) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview

Theme design by Jelle Druyts