MSBuild 4.0 Inline Task

 

The previous posting made use of property functions to allow for non-standard build steps within an MSBuild project. However, MSBuild added another extensibility mechanism – Inline tasks, which, good or bad, allows for direct integration/ injection of any custom logic explainable in .NET CodeDom language (C#, VB, etc.) into a MSBuild project.

An Inline Task is more or less the injection of function and data (source code) into a hosted-environment (task and task factory) which is executed at run-time by MSBuild via the UsingTask task. Actually, source code is embedded into a temporary source file, compiled and then used by MSBuild on the fly.

Now, this extension point enables the build developer to closely package build project and related external tasks. With respect to this case it merely serves as a vehicle to avoid creation of the desired functionality in a separate assembly. Clearly, more advanced needs would still remain within a separately developed, tested and versioned task class. But the simple, yet predominant technology demonstration vehicle - “Hello World” – may exist excellently within an MSBuild project container.

For the sake of this post, the following code tries to mimic the previously shown MSBuild – Faculty using an Inline Task. This does comes at the expense of a less MSBuild-like feeling but with the advantage of less recursion and data copying.

 <!--Author: Christian Bitter-->
<!--Date: 2010.8.2-->
<!--Desc: Simple MSBuild Inline Task Sample-->

<Project ToolsVersion="4.0" xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Faculty Condition="$(Faculty) == ''">0</Faculty>
  </PropertyGroup>
  <!--declare the inline task-->
  <UsingTask
    TaskName="ComputeFacultyOfNumberTask"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
    <ParameterGroup>
      <FacultyParam Required="True" ParameterType="System.Int32"/>
      <Result ParameterType="System.Int32" Output="True"/>
    </ParameterGroup>
    <Task>
      <Reference Include="mscorlib" />
      <Using Namespace="System" />
      <Code Type="Fragment" Language="cs">

        <![CDATA[
          int temp = 1;
          int loop = FacultyParam;
          while (loop > 1)
          {
            temp = temp * loop;
            loop -= 1;
          }
          
          Result = temp;
        ]]>

      </Code>
    </Task>
  </UsingTask>

  <Target Name="FacultyOf">
    <!--
    call the previously defined task with in and out 
    parameters
    -->
    <ComputeFacultyOfNumberTask FacultyParam="$(Faculty)">
      <Output PropertyName="FacultyResult" TaskParameter="Result" />
    </ComputeFacultyOfNumberTask>

    <Message Text="The Faculty of $(Faculty) Is $(FacultyResult)" 
             Importance="High"/>

  </Target>

</Project>