共用方式為


MSBuild 內建工作

MSBuild 工作通常是藉由編譯實作 介面的 ITask 類別所建立。 如需詳細資訊,請參閱 工作

當您想要避免建立已編譯工作的額外負荷時,您可以在專案檔或匯入的檔案中內嵌建立工作。 您不需要建立個別的元件來裝載工作。 使用內嵌工作可讓您更輕鬆地追蹤原始程式碼,並更輕鬆地部署工作。 原始程式碼會整合到 MSBuild 專案檔或匯入的檔案中,通常是 .targets 檔案。

您可以使用程式 代碼工作處理站建立內嵌工作。 針對目前的開發,請務必使用 RoslynCodeTaskFactory,而不是 CodeTaskFactoryCodeTaskFactory 僅支援最多 4.0 的 C# 版本。

內嵌工作是為了方便不需要複雜相依性的小型工作。 內嵌工作的偵錯支援有限。 當您想要撰寫更複雜的程式代碼、參考 NuGet 套件、執行外部工具,或執行可能會產生錯誤狀況的作業時,建議建立已編譯的工作,而不是內嵌工作。 此外,每次建置時都會編譯內嵌工作,因此可能會對建置效能造成明顯影響。

內嵌工作的結構

內嵌工作是由 UsingTask 元素所包含。 內嵌工作和 UsingTask 包含它的元素通常包含在檔案中 .targets ,並視需要匯入至其他項目檔。 以下是不會執行任何動作的基本內嵌工作,但說明語法:

 <!-- This simple inline task does nothing. -->
  <UsingTask
    TaskName="DoNothing"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
    <ParameterGroup />
    <Task>
      <Reference Include="" />
      <Using Namespace="" />
      <Code Type="Fragment" Language="cs">
      </Code>
    </Task>
  </UsingTask>

UsingTask 範例中的 元素有三個屬性,可描述工作,以及編譯工作的內嵌工作處理站。

  • 屬性會 TaskName 命名工作,在此案例中為 DoNothing

  • 屬性會 TaskFactory 命名實作內嵌工作處理站的類別。

  • 屬性 AssemblyFile 會提供內嵌工作處理站的位置。 或者,您可以使用 AssemblyName 屬性來指定內嵌工作處理站類別的完整名稱,通常位於 $(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll

工作的其餘元素是空的 DoNothing ,並提供來說明內嵌工作的順序和結構。 本文稍後會提供完整的範例。

  • ParameterGroup 項目是選擇性的。 指定時,它會宣告工作的參數。 如需輸入和輸出參數的詳細資訊,請參閱本文稍後的 輸入和輸出參數

  • 元素 Task 描述並包含工作原始程式碼。

  • 元素 Reference 會指定您在程式代碼中使用之 .NET 元件的參考。 使用這個項目相當於在Visual Studio中加入項目的參考。 屬性 Include 會指定參考元件的路徑。 mscorlib、.NET Standard、 Microsoft.Build.FrameworkMicrosoft.Build.Utilities.Core 中的元件,以及一些以可轉移方式參考為相依性的元件,都可以在沒有 的情況下 Reference使用。

  • 元素 Using 會列出您想要存取的命名空間。 這個項目相當於 using C# 中的 指示詞。 屬性 Namespace 會指定要包含的命名空間。 它無法將指示詞放在 using 內嵌程序代碼中,因為該程式代碼會放入方法主體中,其中不允許指示 using 詞。

ReferenceUsing 元素與語言無關。 內嵌工作可以用 Visual Basic 或 C# 撰寫。

備註

專案所包含的 Task 元素是工作處理站特定的專案,在此案例中為程式碼工作處理站。

Code 元素

要出現在專案內的 Task 最後一個子專案是 Code 專案。 元素 Code 包含或找出您要編譯為工作的程序代碼。 您放入元素的內容 Code 取決於您要撰寫工作的方式。

屬性 Language 會指定撰寫程式代碼的語言。 適用於 C# 的可接受的值 csvb 適用於 Visual Basic。

屬性 Type 會指定 元素中找到 Code 的程式代碼類型。

  • 如果 值為 TypeClass,則 Code 專案會包含衍生自 介面之 ITask 類別的程序代碼。

  • 如果的值TypeMethod,則程式代碼會定義 介面方法的ITask覆寫Execute

  • 如果的值 TypeFragment,則程式代碼會定義 方法的內容 Execute ,但不會定義簽章或 return 語句。

程序代碼本身通常會出現在標記和]]>標記之間<![CDATA[。 因為程式代碼位於 CDATA 區段中,因此您不必擔心逸出保留字元,例如 “<” 或 “>”。

或者,您可以使用 Source 項目的 屬性 Code 來指定包含工作程式代碼的檔案位置。 原始程式檔中的程式代碼必須是 屬性所 Type 指定的類型。 Source如果屬性存在,則預設值TypeClass。 如果 Source 不存在,則預設值為 Fragment

備註

在原始程式檔中定義工作類別時,類別名稱必須與對應 UsingTask 元素的 屬性一致TaskName

HelloWorld

以下是簡單內嵌工作的範例。 HelloWorld 工作會在默認錯誤記錄裝置上顯示 “Hello, world!” ,通常是系統控制台或 Visual Studio 輸出 視窗。

<Project>
  <!-- This simple inline task displays "Hello, world!" -->
  <UsingTask
    TaskName="HelloWorld"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
    <ParameterGroup />
    <Task>
      <Using Namespace="System"/>
      <Using Namespace="System.IO"/>
      <Code Type="Fragment" Language="cs">
<![CDATA[
// Display "Hello, world!"
Log.LogError("Hello, world!");
]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

您可以將 HelloWorld 工作儲存在名為 HelloWorld.targets 的檔案中,然後將它從專案叫用,如下所示。

<Project>
  <Import Project="HelloWorld.targets" />
  <Target Name="Hello">
    <HelloWorld />
  </Target>
</Project>

輸入和輸出參數

內嵌工作參數是 專案的子專案 ParameterGroup 。 每個參數都會採用定義它的項目名稱。 下列程式代碼會定義 參數 Text

<ParameterGroup>
  <Text />
</ParameterGroup>

參數可能有一或多個下列屬性:

  • Required 是預設的 false 選擇性屬性。 如果 true為 ,則參數為必要參數,而且必須在呼叫工作之前提供值。
  • ParameterType 是預設的 System.String 選擇性屬性。 它可以設定為任何完整的型別,這些型別是專案,或是可以使用 來回轉換成字串 ChangeType的值。 (換句話說,任何可以傳遞至外部工作和從外部工作的類型。
  • Output 是預設的 false 選擇性屬性。 如果 true為 ,則參數必須在從 Execute 方法傳回之前提供值。

例如,

<ParameterGroup>
  <Expression Required="true" />
  <Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
  <Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>

定義這三個參數:

  • Expression 是 System.String 類型的必要輸入參數。

  • Files 是必要的專案清單輸入參數。

  • Tally 是 System.Int32 類型的輸出參數。

Code如果專案具有 TypeMethodFragment 屬性,則會自動為每個參數建立屬性。 否則,必須在工作原始碼中明確宣告屬性,而且必須完全符合其參數定義。

對內嵌工作進行偵錯

MSBuild 會產生內嵌工作的來源檔案,並將輸出寫入暫存盤資料夾 AppData\Local\Temp\MSBuildTemp 中具有 GUID 檔名的文本檔。 輸出通常會刪除,但若要保留此輸出檔案,您可以將環境變數 MSBUILDLOGCODETASKFACTORYOUTPUT 設定為 1。

範例 1

下列內嵌工作會將指定檔案中每個出現的令牌取代為指定的值。

<Project>

  <UsingTask TaskName="TokenReplace" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
    <ParameterGroup>
      <Path ParameterType="System.String" Required="true" />
      <Token ParameterType="System.String" Required="true" />
      <Replacement ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs"><![CDATA[
string content = File.ReadAllText(Path);
content = content.Replace(Token, Replacement);
File.WriteAllText(Path, content);

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

  <Target Name='Demo' >
    <TokenReplace Path="Target.config" Token="$MyToken$" Replacement="MyValue"/>
  </Target>
</Project>

範例 2

下列內嵌工作會產生串行化輸出。 這個範例示範輸出參數和參考的使用方式。

<Project>
  <PropertyGroup>
    <RoslynCodeTaskFactoryAssembly Condition="$(RoslynCodeTaskFactoryAssembly) == ''">$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll</RoslynCodeTaskFactoryAssembly>
  </PropertyGroup>

    <UsingTask 
    TaskName="MyInlineTask" 
    TaskFactory="RoslynCodeTaskFactory" 
    AssemblyFile="$(RoslynCodeTaskFactoryAssembly)">
    <ParameterGroup>
      <Input ParameterType="System.String" Required="true" />
      <Output ParameterType="System.String" Output="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System.Text.Json" /> <!-- Reference an assembly -->
      <Using Namespace="System.Text.Json" />   <!-- Use a namespace -->
      <Code Type="Fragment" Language="cs">
        <![CDATA[
          Output = JsonSerializer.Serialize(new { Message = Input });
        ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="RunInlineTask">
    <MyInlineTask Input="Hello, Roslyn!" >
      <Output TaskParameter="Output" PropertyName="SerializedOutput" />
    </MyInlineTask>
    <Message Text="Serialized Output: $(SerializedOutput)" />
  </Target>
</Project>