Wednesday, October 10, 2007

Create custom task for MSBuild - Step by Step

This is the 2nd post in the msbuild posts series. The first post was an introduction to MSBuild and give you tasting of the basics.

In order to extend Team Foundation Build by plugging in your own logic and tasks, you must write a custom task and use it in your build script (the .proj file).

Custom MSBuild task must be implemented as a .NET class that implements the ITask interface, which is defined in the Microsoft.Build.Framework.dll assembly. You can implement your task in the following two ways:

  1. Derive your class directly from ITask and implement the methods on this interface. or
  2. Derive your class from the helper class, Task (an abstract base class that is a default implementation for BuildEngine and HostObject properties) which is defined in the Microsoft.Build.Utilities.dll assembly. Choosing this option makes it easier to log events from your task.

In both cases you must implement (ITask) or override (Task) it's Execute method. I override this mwthod with a very simple logic to just log a string value to the Build log as you see below.

Step 1 - Creating project

Create Class Library project with a class and a reference to Microsoft.Build.Utilities assembly. I'll derive the class from the Task abstract class and override the Execute method.

Step 2 - Writing the task

Execute function must return true if task has executed successfully otherwise it must return false. Now I will add my code to the Execute method - this is my logic which I want to be executed during the build process. I also add a property to the class (Message) and set an attribute to it [Required] (line 29) - this indicates that msbuild must pass a parameter to the task. The Log ( line 17,24) object I use is the LoggingHelper of the Build Utilities (defined at Microsoft.Build.Utilities.dll )

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Text;
   4:  using Microsoft.Build.Utilities;
   5:  using Microsoft.Build.Framework;
   7:  namespace MSBuildTasks
   8:  {
   9:      public class MyTask:Task
  10:      {
  11:          private string message;
  13:          public override bool Execute()
  14:          {
  15:              try
  16:              {
  17:                  Log.LogMessage(
  18:                      String.Format("This is the message from my task: {0}",
  19:                      message));
  20:                  return true;
  21:              }
  22:              catch
  23:              {
  24:                  Log.LogError("Error occured in my task!");
  25:                  return false;
  26:              }
  27:          }
  29:          [Required]
  30:          public string Message
  31:          {
  32:              get { return message; }
  33:              set { message = value; }
  34:          } 
  36:      }
  37:  }

Now compile the project.

Step 3 - Registering the task in MSBuild file

Now we need to import and register this custom task to the MSBuild file we want to extend (This is because MSBuild must know how to locate the assembly that contains the task class.) . We'll do it by editing the .proj file of the build and add a <UsingTask> element which is a direct child of root <Project> element.  This element has a TaskName attribute to get the name of the task class and an AssemblyFile attribute to get the name or address of the assembly where this class is implemented in.

TaskName="MSBuildTasks.MyTask" AssemblyFile="C:\Work\Projects\Samples\MSBuild\MSBuildTasks\bin\Debug\MSBuildTasks.dll"/>

Step 4 - Calling the task from MSBuild

Calling the task depends on the point in the build process where we want to call. We should choose the point in the process that we want to call the task and add the following under it:

   1:  <Target Name="MyTaskTarget">
   2:      <MyTask Message="Hi MSBuild" />
   3:    </Target>

Line 2 calls the task. The message here is the required parameter to pass to the task.

Step 5 - Running the MSBuild file

After all of that you should run the msbuild file.

This is my MSBuild file (.proj extension)

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="">
<UsingTask TaskName="MSBuildTasks.MyTask"
AssemblyFile="C:\MSBuildTasks\MSBuildTasks.dll" />
<Target Name="MyTaskTarget">
<MyTask Message = "Hi MsBuild"/>

This is the output of the example.



See you in the next post of the MSBuild series.

Technorati Tags:

No comments: