HOW TO: Writing Custom Tasks – Part II – Types and Task Parameters

In Part I of the series on writing custom tasks, I covered the basic mechanics behind implementing your own custom task.  And I had promised that I'd cover the details on the types of task parameters that are supported today.  So here we go.

The simplest and most straightforward "type" for a task parameter is what I already covered in my previous post - i.e. String type.  But what if I really wanted to define a property like shown below?

   public DateTime BuildDate
      get { return buildDate; }
      set { buildDate = value; }

Well - believe it or not, this works today.  This is how you would use such a property:

   <SomeTaskThatLabelsSourceSafe BuildDate="15-Jun-2005" ….>

What this essentially means is that within the task, you will have a true DateTime object that represents the date you passed in via the project file.  Useful, isn't it?

Here are the various data types that you can use for defining properties today. 

  • Boolean
  • Byte
  • Char
  • Decimal
  • Double
  • Int16
  • Int32
  • Int64
  • SByte
  • Single
  • String
  • UInt16
  • UInt32
  • UInt64

These types work well - especially if you are dealing with single value / non - structured task parameters. What if you wanted representation that is a bit more richer?  Metadata is what I am thinking about here - and metadata is the single most coolest aspect of "items" in MSBuild.

So, here's a quick refresher: Metadata is defined on items as shown below. I have a single piece of metadata called Artist on an item that represents an mp3 file:

      <MP3 Include="BlackDog.mp3">
         <Artist>Led Zeppelin</Artist>
In order for a task to be able to effectively deal with items, simply define the task parameter type as ITaskItem.  Here's an example:

   public ITaskItem MusicFile
      get { return mp3File; }
      set { mp3File = value; }

Defining a task parameter as ITaskItem allows you to use methods such as GetMetadata, SetMetadata, RemoveMetadata on mp3File, within the code for the custom task.

So how do I pass an item into a task that supports this task parameter?  Once again pretty straightforward - without any bearing on the actual type of the task parameter itself.  What's shown below works regardless of whether MusicFile is defined as ITaskItem or string or any other type we have discussed so far.

   <PlayMusic MusicFile="@(MP3)" />

Also, you don't necessarily have to use a pre-defined item to pass into the task.  MSBuild is capable of dealing with verbatim strings as values for ITaskItem type of parameters - as shown:

   <PlayMusic MusicFile="BlackDog.mp3" />
The final aspect of data types that I'd like to cover is idea of item collections. 

Supporting collections in your task parameter is simply a matter of defining your task parameter as an array of any of the types we have discussed so far.  So ITaskItem[] would be the choice if you wanted to deal with more than one mp3 file in the last example.

Invoke the task and pass in multiple items like this:

   <!-- MP3File contains more than one song -->
   <PlayMusic MusicFiles="@(MP3File)" />

Alternatively, you can pass in more than one item verbatim like this:

   <PlayMusic MusicFiles="BlackDog.mp3;ZooStation.mp3" />

That's about it for Part II 🙂  Do tell us how we can improve on these posts.  If you would like me to cover any specific aspects that I have not discussed already, just holler and I'll be sure to write about it.

[ Author: Faisal Mohamood ]

Comments (4)

  1. ColinBowern says:

    If I have an ItemGroup defined as follows:

    <DatabaseSnapshots Include="$(MSBuildProjectDirectory)*.scpxml" />

    And in my custom task I want to cycle through the list of items.  Is there any particular advantage to using ITaskItem[] over a string[]?  I have no need for extra metadata – just the array of paths that are calculated.

  2. Neil says:

    The benefit to using ITaskItem[] is that the metadata will persist as it flows through your task. Even though you don’t need it, someone else down the chain might. If you use string[] in your task then the metadata will get dropped.

    If you want to build a more robust task that plays nicely with others you should use ITaskItem[], and then do .ItemSpec on it to get the full filename.

    Hope this helps,


  3. Natasha says:

    I am using ReadLinesFromFile to read lines from the file. the txt file has multiple files, i need to read one line and append it to the path in sql.execute command. how do I use ITaskItem as an array


    <ReadLinesFromFile File="Version.txt">

         <Output TaskParameter="Lines"

           PropertyName="Prop1" />


    <Sql.Execute ServerName="$(ServerName)" DatabaseName="CDRController"


    The above code works if I have only one line in the txt file.

  4. Hi, nice post! I enjoy reading it.

    Keep it coming!

Skip to main content