撰寫 MSBuild 工作

工作包含在 MSBuild 目標中,並提供在建置程式期間執行的程式代碼。 MSBuild 包含常見任務的程式庫,您也可以建立自己的任務。 如需 MSBuild 包含之工作連結庫的詳細資訊,請參閱 MSBuild 工作參考。

先決條件

使用 MSBuild 建置的 Visual Studio 專案。

任務

MSBuild 工作的範例包括 Copy、複製一或多個檔案、建立目錄的 MakeDir,以及編譯 C# 原始程式碼檔案 的 Csc。 每個工作都實作為 .NET 類別,並實作 ITask 組件中定義的 介面。

當您實作工作時,可以使用下列其中一種方法:

  • 直接實作 ITask 介面。

  • 從 helper 類別 Task衍生您的類別,該類別定義於 Microsoft.Build.Utilities.dll 元件中。 Task 會實作 ITask 並提供某些 ITask 成員的預設實作。 記錄也比較容易。

在這兩種情況下,您必須將方法新增至名為 Execute的類別,此類別會在工作執行時呼叫。 此方法不接受任何參數,並傳回 Boolean 值:如果工作成功,則為 true,如果工作失敗,則為 false。 下列範例顯示不執行任何動作、順利完成的工作,並傳 true回 。

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace MyTasks
{
    public class SimpleTask : Task
    {
        public override bool Execute()
        {
            return true;
        }
    }
}

下列 MSBuild 專案檔會執行上述工作:

<Project>
    <Target Name="MyTarget">
        <SimpleTask />
    </Target>
</Project>

當工作執行時,如果您在工作類別上建立 .NET 屬性,也可以從項目檔接收輸入。 MSBuild 會在呼叫工作的 Execute 方法之前,立即設定這些屬性。 若要建立字串屬性,請使用工作程式代碼,例如下列範例:

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace MyTasks
{
    public class SimpleTask : Task
    {
        public override bool Execute()
        {
            return true;
        }

        public string MyProperty { get; set; }
    }
}

下列項目檔會執行此工作,並將 設定 MyProperty 為指定的值。

<Project>
   <Target Name="MyTarget">
      <SimpleTask MyProperty="Value for MyProperty" />
   </Target>
</Project>

MSBuild 如何叫用任務

當 MSBuild 叫用工作時,它會先具現化工作類別,然後針對項目檔中工作元素中設定的工作參數呼叫該對象的屬性 setter。 如果 task 元素未指定參數,或元素中指定的表達式評估為空字串,則不會呼叫屬性 setter。

例如,在下列專案中,只會呼叫Input3的setter。

<Project>
 <Target Name="InvokeCustomTask">
  <CustomTask Input1=""
              Input2="$(PropertyThatIsNotDefined)"
              Input3="value3" />
 </Target>
</Project>

工作不應該相依於參數屬性 setter 調用的任何相對順序。

工作參數類型

MSBuild 原生支援屬性類型string、bool、ITaskItem 和 ITaskItem[]。 如果任務接受不同類型的參數,MSBuild 會叫用 ChangeType 將 string(包括所有展開的屬性和項目參考)轉換為目的類型。 如果任何輸入參數的轉換失敗,MSBuild 會發出錯誤,而且不會呼叫工作的 Execute() 方法。

註冊任務

若要執行工作,MSBuild 必須知道如何找出並執行包含工作類別的元件。 工作使用 UsingTask 元素(MSBuild)註冊。

如果您的工作具有特定運行時間的相依性,您必須指示 MSBuild 在特定環境中執行此工作,方法是在其 Architecture 元素中指出 Runtime 和 UsingTask 屬性。 如需詳細資訊,請參閱 UsingTask屬性和工作參數。

MSBuild 檔案 Microsoft.Common.tasks 是專案檔,列出 UsingTask 註冊 MSBuild 所提供之所有工作的元素。 MSBuild 建置任何專案時,會自動包含此檔案。 如果 已在 Microsoft.Common.tasks 中註冊的工作也註冊在目前的項目檔中,則目前的專案檔會優先使用,因此您可以使用同名自己的工作覆寫預設工作。

提示

您可以檢視其 Microsoft.Common.tasks 檔案的內容,以查看特定 MSBuild 版本提供的工作清單。

需要設定工作屬性

您可以將特定工作屬性標示為必要,因此執行工作的任何專案檔都必須設定這些屬性的值,否則組建會失敗。 將 [Required] 屬性套用至工作中的 .NET 屬性,如下所示:

[Required]
public string RequiredProperty { get; set; }

[Required] 屬性是由 RequiredAttribute 命名空間中的 Microsoft.Build.Framework 所定義。

從任務引發事件

如果您的任務衍生自 Task 輔助類別,您可以在 Task 類別中使用下列任何輔助方法來引發這些事件,所有已註冊的記錄器都能攔截並顯示這些事件。

public override bool Execute()
{
    Log.LogError("messageResource1", "1", "2", "3");
    Log.LogWarning("messageResource2");
    Log.LogMessage(MessageImportance.High, "messageResource3");
    ...
}

如果您的工作直接實作 ITask ,您仍然可以引發這類事件,但必須使用 IBuildEngine 介面。 下列範例示範實作 ITask 和引發自定義事件的工作。

public class SimpleTask : ITask
{
    public IBuildEngine BuildEngine { get; set; }

    public override bool Execute()
    {
        TaskEventArgs taskEvent =
            new TaskEventArgs(BuildEventCategory.Custom,
            BuildEventImportance.High, "Important Message",
           "SimpleTask");
        BuildEngine.LogBuildEvent(taskEvent);
        return true;
    }
}

打包任務

分發任務的建議方式是透過 NuGet 套件。 套件必須包含所有的相依項目。 如需逐步引導您建立自定義工作的教學課程,請參閱 建立 NuGet 套件。

範例 1

下列 C# 類別示範衍生自 Task 協助程式類別的工作。 此工作會傳回 true,表示它成功。

using System;
using Microsoft.Build.Utilities;

namespace SimpleTask1
{
    public class SimpleTask1: Task
    {
        public override bool Execute()
        {
            // This is where the task would presumably do its work.
            return true;
        }
    }
}

範例 2

下列 C# 類別示範實作 ITask 介面的工作。 此工作會傳回 true,表示它成功。

using System;
using Microsoft.Build.Framework;

namespace SimpleTask2
{
    public class SimpleTask2: ITask
    {
        //When implementing the ITask interface, it's necessary to
        //implement a BuildEngine property of type
        //Microsoft.Build.Framework.IBuildEngine. This is done for
        //you if you derive from the Task class.
        public IBuildEngine BuildEngine { get; set; }

        // When implementing the ITask interface, it's necessary to
        // implement a HostObject property of type object.
        // This is done for you if you derive from the Task class.
        public object HostObject { get; set; }

        public bool Execute()
        {
            // This is where the task does its work.
            return true;
        }
    }
}

範例 3

這個 C# 類別示範衍生自協助程式類別 Task 的工作。 工作具有必要的字串屬性,並引發所有已註冊記錄器所顯示的事件。

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace SimpleTask3
{
    public class SimpleTask3 : Task
    {
        private string myProperty;

        // The [Required] attribute indicates a required property.
        // If a project file invokes this task without passing a value
        // to this property, the build will fail immediately.
        [Required]
        public string MyProperty
        {
            get
            {
                return myProperty;
            }
            set
            {
                myProperty = value;
            }
        }

        public override bool Execute()
        {
            // Log a high-importance comment
            Log.LogMessage(MessageImportance.High,
                "The task was passed \"" + myProperty + "\".");
            return true;
        }
    }
}

範例 4

下列範例顯示一個專案檔案,該檔案呼叫了上一個範例工作。SimpleTask3

<Project>
    <UsingTask TaskName="SimpleTask3.SimpleTask3"
        AssemblyFile="SimpleTask3\bin\debug\simpletask3.dll"/>

    <Target Name="MyTarget">
        <SimpleTask3 MyProperty="Hello!"/>
    </Target>
</Project>