Freigeben über


MSBuild-Inlineaufgaben

MSBuild-Aufgaben werden in der Regel durch Kompilieren einer Klasse erstellt, die die ITask Schnittstelle implementiert. Weitere Informationen finden Sie unter Aufgaben.

Wenn Sie den Aufwand für die Erstellung eines kompilierten Vorgangs vermeiden möchten, können Sie einen Vorgang inline in der Projektdatei oder in einer importierten Datei erstellen. Sie müssen keine separate Assembly erstellen, um die Aufgabe zu hosten. Die Verwendung einer Inlineaufgabe erleichtert das Nachverfolgen des Quellcodes und die Bereitstellung der Aufgabe. Der Quellcode ist in die MSBuild-Projektdatei oder importierte Datei integriert, in der Regel eine .targets Datei.

Sie erstellen eine Inline-Aufgabe mithilfe einer Codeaufgabenfabrik. Achten Sie bei der aktuellen Entwicklung darauf, RoslynCodeTaskFactory zu verwenden, nicht CodeTaskFactory. CodeTaskFactory unterstützt nur C#-Versionen bis zu 4.0.

Inlineaufgaben sind als Komfort für kleine Vorgänge gedacht, die keine komplizierten Abhängigkeiten erfordern. Die Debuggingunterstützung für Inlineaufgaben ist begrenzt. Es wird empfohlen, eine kompilierte Aufgabe anstelle einer Inlineaufgabe zu erstellen, wenn Sie komplexeren Code schreiben möchten, auf ein NuGet-Paket verweisen, externe Tools ausführen oder Vorgänge ausführen, die Fehlerbedingungen erzeugen könnten. Außerdem werden Inlineaufgaben jedes Mal kompiliert, wenn Sie ein Build durchführen, was sich spürbar auf die Buildleistung auswirken kann.

Die Struktur einer Inline-Aufgabe

Eine Inlineaufgabe ist in einem UsingTask-Element enthalten. Die Inlineaufgabe und das UsingTask darin enthaltene Element sind in der Regel in einer .targets Datei enthalten und bei Bedarf in andere Projektdateien importiert. Hier ist eine einfache Inlineaufgabe, die nichts tut, aber die Syntax veranschaulicht:

 <!-- 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>

Das UsingTask-Element im Beispiel verfügt über drei Attribute, die die Aufgabe und die Inline-Aufgabenfabrik beschreiben, durch die sie kompiliert wird.

  • Das TaskName Attribut benennt die Aufgabe in diesem Fall DoNothing.

  • Das TaskFactory Attribut benennt die Klasse, die die Inline-Task-Fabrik implementiert.

  • Das AssemblyFile Attribut gibt den Speicherort der Inline-Task-Factory an. Alternativ können Sie das AssemblyName-Attribut verwenden, um den vollqualifizierten Namen der Inline-Task-Factory-Klasse anzugeben, die sich typischerweise in $(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll befindet.

Die verbleibenden Elemente des DoNothing Vorgangs sind leer und werden bereitgestellt, um die Reihenfolge und Struktur eines Inlinevorgangs zu veranschaulichen. Ein vollständiges Beispiel wird weiter unten in diesem Artikel vorgestellt.

  • Das ParameterGroup-Element ist optional. Wenn angegeben, deklariert sie die Parameter für den Vorgang. Weitere Informationen zu Eingabe- und Ausgabeparametern finden Sie weiter unten in diesem Artikel unter Eingabe- und Ausgabeparameter .

  • Das Task Element beschreibt und enthält den Quellcode der Aufgabe.

  • Das Reference Element gibt Verweise auf die .NET-Assemblys an, die Sie in Ihrem Code verwenden. Die Verwendung dieses Elements entspricht dem Hinzufügen eines Verweises auf ein Projekt in Visual Studio. Das Include Attribut gibt den Pfad der Assembly an, auf die verwiesen wird. Assemblys in mscorlib, .NET Standard, Microsoft.Build.Framework und Microsoft.Build.Utilities.Core sowie einige Assemblys, auf die transitiv als Abhängigkeiten verwiesen wird, sind ohne Reference verfügbar.

  • Das Using Element listet die Namespaces auf, auf die Sie zugreifen möchten. Dieses Element entspricht der using Direktive in C#. Das Namespace Attribut gibt den einzuschließden Namespace an. Es funktioniert nicht, eine using Direktive in den Inlinecode einzufügen, da dieser Code in einen Methodentext eingefügt wird, in dem using Direktiven nicht zulässig sind.

Reference und Using Elemente sind sprachunabhängig. Inlineaufgaben können in Visual Basic oder C# geschrieben werden.

Hinweis

Elemente, die vom Task-Element enthalten werden, sind spezifisch für die Task-Factory, in diesem Fall die Code-Task-Factory.

Code-Element

Das letzte untergeordnete Element, das innerhalb des Task Elements angezeigt werden soll, ist das Code Element. Das Code Element enthält oder sucht den Code, den Sie in einer Aufgabe kompilieren möchten. Was Sie in das Code Element einfügen, hängt davon ab, wie Sie die Aufgabe schreiben möchten.

Das Language Attribut gibt die Sprache an, in der Ihr Code geschrieben wird. Zulässige Werte sind cs für C# vb für Visual Basic.

Das Type-Attribut gibt den Codetyp an, der im Code-Element vorliegt.

  • Wenn der Wert lautet TypeClass, enthält das Code Element Code für eine Klasse, die von der ITask Schnittstelle abgeleitet wird.

  • Wenn der Wert Type lautet Method, definiert der Code eine Außerkraftsetzung der Execute Methode der ITask Schnittstelle.

  • Wenn der Wert von Type ist Fragment, definiert der Code den Inhalt der Execute Methode, aber nicht die Signatur oder die return Anweisung.

Der Code selbst wird in der Regel zwischen einer <![CDATA[ Markierung und einer ]]> Markierung angezeigt. Da sich der Code in einem CDATA-Abschnitt befindet, müssen Sie sich keine Gedanken darüber machen, reservierte Zeichen zu entfernen, z. B. "<" oder ">".

Alternativ können Sie das Source Attribut des Code Elements verwenden, um den Speicherort einer Datei anzugeben, die den Code für ihre Aufgabe enthält. Der Code in der Quelldatei muss vom Typ sein, der durch das Type Attribut angegeben wird. Wenn das Source Attribut vorhanden ist, ist der Standardwert von TypeClass. Wenn Source nicht vorhanden, lautet Fragmentder Standardwert .

Hinweis

Beim Definieren der Aufgabenklasse in der Quelldatei muss der Klassenname dem TaskName Attribut des entsprechenden UsingTask-Elements zustimmen.

HelloWorld

Hier ist ein Beispiel für eine einfache Inlineaufgabe. Die HelloWorld-Aufgabe zeigt "Hello, world!" auf dem Standardmäßigen Fehlerprotokollierungsgerät an, das in der Regel die Systemkonsole oder das Visual Studio-Ausgabefenster ist.

<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>

Sie können den Vorgang "HelloWorld" in einer Datei speichern, die " HelloWorld.targets" heißt, und sie dann wie folgt aus einem Projekt aufrufen.

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

Eingabe- und Ausgabeparameter

Inline-Aufgabenparameter sind untergeordnete Elemente eines ParameterGroup-Elements. Jeder Parameter verwendet den Namen des Elements, das es definiert. Der folgende Code definiert den Parameter Text.

<ParameterGroup>
  <Text />
</ParameterGroup>

Parameter können mindestens eins dieser Attribute aufweisen:

  • Required ist ein optionales Attribut, das standardmäßig ist false . Wenn true, dann ist der Parameter erforderlich und muss vor dem Aufrufen der Aufgabe einen Wert erhalten.
  • ParameterType ist ein optionales Attribut, das standardmäßig ist System.String . Er kann auf jeden vollqualifizierten Typ festgelegt werden, der entweder ein Element oder ein Wert ist, der mithilfe einer ChangeTypeZeichenfolge in und aus einer Zeichenfolge konvertiert werden kann. (Mit anderen Worten, jeder Typ, der an und von einer externen Aufgabe übergeben werden kann.)
  • Output ist ein optionales Attribut, das standardmäßig ist false . Falls true, muss dem Parameter ein Wert zugewiesen werden, bevor von der Execute-Methode zurückgekehrt wird.

Beispiel:

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

definiert die folgenden drei Parameter:

  • Expression ist ein erforderlicher Eingabeparameter vom Typ "System.String".

  • Files ist ein erforderlicher Eingabeparameter für Elementlisten.

  • Tally ist ein Ausgabeparameter vom Typ "System.Int32".

Wenn das Code-Element das Type-Attribut von Fragment oder Method hat, werden Eigenschaften automatisch für jeden Parameter erstellt. Andernfalls müssen Eigenschaften explizit im Aufgabenquellcode deklariert werden und müssen exakt mit ihren Parameterdefinitionen übereinstimmen.

Debuggen einer Inlineaufgabe

MSBuild generiert eine Quelldatei für die Inlineaufgabe und schreibt die Ausgabe in die Textdatei mit einem GUID-Dateinamen im Ordner "Temporäre Dateien", "AppData\Local\Temp\MSBuildTemp". Die Ausgabe wird normalerweise gelöscht, aber um diese Ausgabedatei beizubehalten, können Sie die Umgebungsvariable MSBUILDLOGCODETASKFACTORYOUTPUT auf 1 festlegen.

Beispiel 1

Die folgende Inlineaufgabe ersetzt jedes Vorkommen eines Tokens in der angegebenen Datei durch den angegebenen Wert.

<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>

Beispiel 2

Die folgende Inline-Aufgabe generiert eine Serienausgabe. Dieses Beispiel zeigt die Verwendung eines Ausgabeparameters und eines Verweises.

<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>