MSBuild-Inlineaufgaben mit RoslynCodeTaskFactoryMSBuild inline tasks with RoslynCodeTaskFactory

Ähnlich wie bei CodeTaskFactory verwendet RoslynCodeTaskFactory die plattformübergeifenden Roslyn-Compiler, um In-Memory-Taskassemblys für die Verwendung als Inlinetasks zu generieren.Similar to the CodeTaskFactory, RoslynCodeTaskFactory uses the cross-platform Roslyn compilers to generate in-memory task assemblies for use as inline tasks. RoslynCodeTaskFactory-Tasks sind für .NET Standard vorgesehen und funktionieren ebenfalls mit .NET Framework- und .NET Core-Runtimes sowie auf anderen Plattformen wie Linux und macOS.RoslynCodeTaskFactory tasks target .NET Standard and can work on .NET Framework and .NET Core runtimes as well as other platforms such as Linux and Mac OS.

Note

Der RoslynCodeTaskFactory-Task ist nur in MSBuild 15.8 und höher verfügbar.The RoslynCodeTaskFactory is available in MSBuild 15.8 and above only.

Die Struktur einer Inlineaufgabe mit RoslynCodeTaskFactoryThe structure of an inline task with RoslynCodeTaskFactory

RoslynCodeTaskFactory-Inlineaufgaben werden genau wie bei CodeTaskFactory deklariert. Der einzige Unterschied liegt darin, dass Sie .NET Standard als Ziel verwenden.RoslynCodeTaskFactory inline tasks are declared in an identical way as CodeTaskFactory, the only difference being that they target .NET Standard. Die Inlineaufgabe und das UsingTask-Element, in dem sie enthalten ist, befinden sich in der Regel in einer TARGETS-Datei und werden bei Bedarf in andere Projektdateien importiert.The inline task and the UsingTask element that contains it are typically included in a .targets file and imported into other project files as required. Im Folgenden finden Sie eine einfache Inlineaufgabe.Here is a basic inline task. Beachten Sie, dass mit dieser Aufgabe keine Aktionen ausgeführt werden.Notice that it does nothing.

<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- 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>
</Project>

Das UsingTask-Element im Beispiel besitzt drei Attribute, die die Aufgabe und die Inlineaufgabenfactory beschreiben, die diese kompiliert.The UsingTask element in the example has three attributes that describe the task and the inline task factory that compiles it.

  • Die Aufgabe wird nach dem TaskName-Attribut benannt, in diesem Fall DoNothing.The TaskName attribute names the task, in this case, DoNothing.

  • Nach dem TaskFactory-Attribut wird die Klasse benannt, die die Inlineaufgabenfactory implementiert.The TaskFactory attribute names the class that implements the inline task factory.

  • Über das AssemblyFile-Attribut wird der Speicherort der Inlineaufgabenfactory angegeben.The AssemblyFile attribute gives the location of the inline task factory. Sie können auch mit dem AssemblyName-Attribut den vollqualifizierten Namen der Inlineaufgabenfactory-Klasse angeben, die sich in der Regel im globalen Assemblycache (Global Assembly Cache, GAC) befindet.Alternatively, you can use the AssemblyName attribute to specify the fully qualified name of the inline task factory class, which is typically located in the global assembly cache (GAC).

Die verbleibenden Elemente der DoNothing-Aufgabe sind leer und werden bereitgestellt, um die Reihenfolge und Struktur einer Inlineaufgabe zu veranschaulichen.The remaining elements of the DoNothing task are empty and are provided to illustrate the order and structure of an inline task. Ein robusteres Beispiel wird weiter unten in diesem Thema präsentiert.A more robust example is presented later in this topic.

  • Das ParameterGroup-Element ist optional.The ParameterGroup element is optional. Bei Angabe werden die Parameter für die Aufgabe deklariert.When specified, it declares the parameters for the task. Weitere Informationen zu Eingabe- und Ausgabeparametern finden Sie weiter unten in diesem Artikel unter Eingabe- und Ausgabeparameter.For more information about input and output parameters, see Input and Output Parameters later in this topic.

  • Das Task-Element beschreibt und enthält den Quellcode der Aufgabe.The Task element describes and contains the task source code.

  • Das Reference-Element stellt Verweise auf die im Code verwendeten .NET-Assemblys bereit.The Reference element specifies references to the .NET assemblies that you are using in your code. Dies entspricht dem Hinzufügen eines Verweises auf ein Projekt in Visual Studio.This is equivalent to adding a reference to a project in Visual Studio. Das Include-Attribut gibt den Pfad der Assembly an, auf die verwiesen wird.The Include attribute specifies the path of the referenced assembly.

  • Das Using-Element führt die Namespaces auf, auf die Sie zugreifen möchten.The Using element lists the namespaces that you want to access. Dies ähnelt der Using-Anweisung in Visual C#.This resembles the Using statement in Visual C#. Das Namespace-Attribut gibt den zu einschließenden Namespace an.The Namespace attribute specifies the namespace to include.

Das Reference-Element und das Using-Element sind sprachunabhängig.Reference and Using elements are language-agnostic. Inlineaufgaben können jeder unterstützten .NET CodeDom-Sprache geschrieben werden, z. B. Visual Basic oder Visual C#.Inline tasks can be written in any one of the supported .NET CodeDom languages, for example, Visual Basic or Visual C#.

Note

Elemente im Task-Element sind für die Aufgabenfactory spezifisch, in diesem Fall die Codeaufgabenfactory.Elements contained by the Task element are specific to the task factory, in this case, the code task factory.

CodeelementCode element

Als letztes untergeordnetes Element wird im Task-Element das Code-Element angegeben.The last child element to appear within the Task element is the Code element. Das Code-Element enthält oder sucht den Code, den Sie zu einer Aufgabe kompilieren möchten.The Code element contains or locates the code that you want to be compiled into a task. Welche Elemente Sie im Code-Element einfügen, ist davon abhängig, wie Sie die Aufgabe erstellen möchten.What you put in the Code element depends on how you want to write the task.

Das Language-Attribut gibt die Sprache an, in die der Code geschrieben ist.The Language attribute specifies the language in which your code is written. Zulässige Werte sind cs für C# und vb für Visual Basic.Acceptable values are cs for C#, vb for Visual Basic.

Das Type-Attribut gibt den Typ von Code im Code-Element an.The Type attribute specifies the type of code that is found in the Code element.

  • Wenn der Wert von Type auf Class festgelegt ist, enthält das Code-Element Code für eine Klasse, die von der ITask-Schnittstelle abgeleitet wird.If the value of Type is Class, then the Code element contains code for a class that derives from the ITask interface.

  • Wenn der Wert von Type auf Method festgelegt ist, wird im Code die Execute-Methode der ITask-Schnittstelle überschrieben.If the value of Type is Method, then the code defines an override of the Execute method of the ITask interface.

  • Wenn der Wert von Type auf Fragment festgelegt ist, wird im Code der Inhalt der Execute-Methode, nicht jedoch die Signatur oder die return-Anweisung definiert.If the value of Type is Fragment, then the code defines the contents of the Execute method, but not the signature or the return statement.

Der Code selbst befindet sich in der Regel zwischen einem <![CDATA[-Marker und einem ]]>-Marker.The code itself typically appears between a <![CDATA[ marker and a ]]> marker. Da sich der Code in einem CDATA-Abschnitt befindet, müssen Sie reservierte Zeichen, z.B. „<“ oder „>“, nicht mit Escapezeichen versehen.Because the code is in a CDATA section, you do not have to worry about escaping reserved characters, for example, "<" or ">".

Sie können den Speicherort einer Datei mit dem Code für die Aufgabe auch über das Source-Attribut des Code-Elements angeben.Alternatively, you can use the Source attribute of the Code element to specify the location of a file that contains the code for your task. Der Code in der Quelldatei muss den vom Type-Attribut angegebenen Typ aufweisen.The code in the source file must be of the type that is specified by the Type attribute. Bei vorhandenem Source-Attribut ist der Standardwert von Type Class.If the Source attribute is present, the default value of Type is Class. Wenn Source nicht vorhanden ist, lautet der Standardwert Fragment.If Source is not present, the default value is Fragment.

Note

Bei der Definition der Aufgabenklasse in der Quelldatei muss der Klassenname mit dem TaskName-Attribut des entsprechenden UsingTask-Elements übereinstimmen.When defining the task class in the source file, the class name must agree with the TaskName attribute of the corresponding UsingTask element.

Hello WorldHello World

Im Folgenden sehen Sie einen robusteren Inlinetask mit RoslynCodeTaskFactory:Here is a more robust inline task with RoslynCodeTaskFactory. Die HalloWelt-Aufgabe gibt „Hallo, Welt!“The HelloWorld task displays "Hello, world!" auf dem Standardgerät für die Fehlerprotokollierung aus. In der Regel handelt es sich dabei um die Systemkonsole oder das Fenster Ausgabe in Visual Studio.on the default error logging device, which is typically the system console or the Visual Studio Output window. Das Reference-Element im Beispiel wurde nur zur Veranschaulichung eingefügt.The Reference element in the example is included just for illustration.

<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- This simple inline task displays "Hello, world!" -->
  <UsingTask
    TaskName="HelloWorld"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
    <ParameterGroup />
    <Task>
      <Reference Include="System.Xml"/>
      <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 die HelloWorld-Aufgabe in der Datei HelloWorld.targets speichern und anschließend wie folgt in einem Projekt aufrufen.You could save the HelloWorld task in a file that is named HelloWorld.targets, and then invoke it from a project as follows.

<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="HelloWorld.targets" />
  <Target Name="Hello">
    <HelloWorld />
  </Target>
</Project>

Eingabe- und AusgabeparameterInput and output parameters

Inlineaufgabenparameter bilden untergeordnete Elemente eines ParameterGroup-Elements.Inline task parameters are child elements of a ParameterGroup element. Jeder Parameter akzeptiert den Namen des Elements, das von ihm definiert wird.Every parameter takes the name of the element that defines it. Im folgenden Code wird der Parameter Text definiert.The following code defines the parameter Text.

<ParameterGroup>
    <Text />
</ParameterGroup>

Parameter können ein oder mehrere Attribute besitzen:Parameters may have one or more of these attributes:

  • Required ist ein optionales Attribut, das standardmäßig den Wert false besitzt.Required is an optional attribute that is false by default. Bei true ist der Parameter erforderlich und muss vor dem Aufrufen der Aufgabe einen Wert erhalten.If true, then the parameter is required and must be given a value before calling the task.

  • ParameterType ist ein optionales Attribut, das standardmäßig den Wert System.String besitzt.ParameterType is an optional attribute that is System.String by default. Es kann auf jeden vollqualifizierten Typ festgelegt werden, bei dem es sich um ein Element oder einen Wert handelt und mit System.Convert.ChangeType in und aus einer Zeichenfolge konvertiert werden kann.It may be set to any fully qualified type that is either an item or a value that can be converted to and from a string by using System.Convert.ChangeType. (Anders gesagt kann jeder Typ an eine und von einer externen Aufgabe übergeben werden.)(In other words, any type that can be passed to and from an external task.)

  • Output ist ein optionales Attribut, das standardmäßig den Wert false besitzt.Output is an optional attribute that is false by default. Bei true muss dem Parameter ein Wert zugewiesen werden, bevor die Execute-Methode die Rückgabe ausführt.If true, then the parameter must be given a value before returning from the Execute method.

Ein auf ein Objekt angewendeterFor example,

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

definiert die folgenden drei Parameter:defines these three parameters:

  • Expression ist ein erforderlicher Eingabeparameter vom Typ System.String.Expression is a required input parameter of type System.String.

  • Files ist ein erforderlicher Eingabeparameter für Elementlisten.Files is a required item list input parameter.

  • Tally ist ein Ausgabeparameter vom Typ System.Int32.Tally is an output parameter of type System.Int32.

Wenn das Code-Element das Type-Attribut Fragment oder Method aufweist, werden für jeden Parameter automatisch Eigenschaften erstellt.If the Code element has the Type attribute of Fragment or Method, then properties are automatically created for every parameter. Andernfalls müssen Eigenschaften explizit im Aufgabenquellcode deklariert werden und exakt mit den zugehörigen Parameterdefinitionen übereinstimmen.Otherwise, properties must be explicitly declared in the task source code, and must exactly match their parameter definitions.

BeispielExample

Der folgende Inlinetask protokolliert einige Meldungen und gibt eine Zeichenfolge zurück.The following inline task logs some messages and returns a string.

<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' ToolsVersion="15.0">

    <UsingTask TaskName="MySample"
               TaskFactory="RoslynCodeTaskFactory"
               AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
        <ParameterGroup>
            <Parameter1 ParameterType="System.String" Required="true" />
            <Parameter2 ParameterType="System.String" />
            <Parameter3 ParameterType="System.String" Output="true" />
        </ParameterGroup>
        <Task>
            <Using Namespace="System" />
            <Code Type="Fragment" Language="C#">
              <![CDATA[
              Log.LogMessage(MessageImportance.High, "Hello from an inline task created by Roslyn!");
              Log.LogMessageFromText($"Parameter1: '{Parameter1}'", MessageImportance.High);
              Log.LogMessageFromText($"Parameter2: '{Parameter2}'", MessageImportance.High);
              Parameter3 = "A value from the Roslyn CodeTaskFactory";
            ]]>
            </Code>
        </Task>
    </UsingTask>

    <Target Name="Demo">
      <MySample Parameter1="A value for parameter 1" Parameter2="A value for parameter 2">
          <Output TaskParameter="Parameter3" PropertyName="NewProperty" />
      </MySample>

      <Message Text="NewProperty: '$(NewProperty)'" />
    </Target>
</Project>

Diese Inlinetasks können Pfade kombinieren und den Dateinamen abrufen.These inline tasks can combine paths and get the file name.

<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' ToolsVersion="15.0">

    <UsingTask TaskName="PathCombine"
               TaskFactory="RoslynCodeTaskFactory"
               AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
        <ParameterGroup>
            <Paths ParameterType="System.String[]" Required="true" />
            <Combined ParameterType="System.String" Output="true" />
        </ParameterGroup>
        <Task>
            <Using Namespace="System" />
            <Code Type="Fragment" Language="C#">
            <![CDATA[
            Combined = Path.Combine(Paths);
            ]]>
            </Code>
        </Task>
    </UsingTask>

    <UsingTask TaskName="PathGetFileName"
             TaskFactory="RoslynCodeTaskFactory"
             AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
        <ParameterGroup>
            <Path ParameterType="System.String" Required="true" />
            <FileName ParameterType="System.String" Output="true" />
        </ParameterGroup>
        <Task>
            <Using Namespace="System" />
            <Code Type="Fragment" Language="C#">
            <![CDATA[
            FileName = System.IO.Path.GetFileName(Path);
            ]]>
            </Code>
        </Task>
    </UsingTask>

    <Target Name="Demo">
        <PathCombine Paths="$(Temp);MyFolder;$([System.Guid]::NewGuid()).txt">
            <Output TaskParameter="Combined" PropertyName="MyCombinedPaths" />
        </PathCombine>

        <Message Text="Combined Paths: '$(MyCombinedPaths)'" />

        <PathGetFileName Path="$(MyCombinedPaths)">
            <Output TaskParameter="FileName" PropertyName="MyFileName" />
        </PathGetFileName>

        <Message Text="File name: '$(MyFileName)'" />
    </Target>
</Project>

Siehe auchSee also