Delen via


MSBuild-inlinetaken

MSBuild-taken worden doorgaans gemaakt door een klasse te compileren die de ITask interface implementeert. Zie Tasksvoor meer informatie.

Als u de overhead van het maken van een gecompileerde taak wilt voorkomen, kunt u een inline taak maken in het projectbestand of in een geïmporteerd bestand. U hoeft geen afzonderlijke assembly te maken om de taak te hosten. Door een inline-taak te gebruiken, is het eenvoudiger om de broncode bij te houden en de taak gemakkelijker te implementeren. De broncode is geïntegreerd in het MSBuild-projectbestand of geïmporteerde bestand, meestal een .targets bestand.

U maakt een inlinetaak met behulp van een codetaakfactory. Voor de huidige ontwikkeling moet u RoslynCodeTaskFactory gebruiken, niet CodeTaskFactory. CodeTaskFactory ondersteunt alleen C#-versies tot 4.0.

Inline-taken zijn bedoeld als gemak voor kleine taken waarvoor geen ingewikkelde afhankelijkheden zijn vereist. Ondersteuning voor foutopsporing voor inlinetaken is beperkt. Het is raadzaam om een gecompileerde taak te maken in plaats van inline-taak wanneer u complexere code wilt schrijven, naar een NuGet-pakket wilt verwijzen, externe hulpprogramma's wilt uitvoeren of bewerkingen wilt uitvoeren die foutvoorwaarden kunnen veroorzaken. Bovendien worden inlinetaken gecompileerd telkens wanneer u bouwt, zodat er een merkbare invloed kan zijn op de prestaties van de build.

De structuur van een inlinetaak

Een inlinetaak is opgenomen in een UsingTask-element . De inlinetaak en het UsingTask element dat deze bevat, worden doorgaans in een .targets bestand opgenomen en indien nodig geïmporteerd in andere projectbestanden. Hier volgt een eenvoudige inline-taak die niets doet, maar de syntaxis illustreert:

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

Het UsingTask element in het voorbeeld heeft drie kenmerken waarmee de taak en de inline-taakfactory worden beschreven waarmee deze wordt gecompileerd.

  • Het TaskName kenmerk noemt de taak in dit geval DoNothing.

  • Het TaskFactory kenmerk geeft de klasse de naam die de inline-taakfactory implementeert.

  • Het AssemblyFile kenmerk geeft de locatie van de inline-taakfactory. U kunt het AssemblyName kenmerk ook gebruiken om de volledig gekwalificeerde naam van de inline-taakfactoryklasse op te geven, die zich meestal in $(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll.

De resterende elementen van de DoNothing taak zijn leeg en worden opgegeven om de volgorde en structuur van een inlinetaak te illustreren. Verderop in dit artikel wordt een volledig voorbeeld weergegeven.

  • Het ParameterGroup element is optioneel. Wanneer dit is opgegeven, worden de parameters voor de taak declareren. Zie invoer- en uitvoerparameters verderop in dit artikel voor meer informatie over invoer- en uitvoerparameters.

  • Het Task element beschrijft en bevat de broncode van de taak.

  • Het Reference element bevat verwijzingen naar de .NET-assembly's die u in uw code gebruikt. Het gebruik van dit element is gelijk aan het toevoegen van een verwijzing naar een project in Visual Studio. Het Include kenmerk geeft het pad op van de assembly waarnaar wordt verwezen. Assembly's in mscorlib, .NET Standard, Microsoft.Build.Framework en Microsoft.Build.Utilities.Core, evenals enkele assembly's waarnaar transitief wordt verwezen als afhankelijkheden, zijn beschikbaar zonder een Reference.

  • Het Using element bevat de naamruimten die u wilt openen. Dit element is gelijk aan de using instructie in C#. Het Namespace kenmerk geeft de naamruimte op die moet worden opgenomen. Het werkt niet om een using richtlijn in de inlinecode te plaatsen, omdat die code in een methodebody wordt geplaatst, waarbij using richtlijnen niet zijn toegestaan.

Reference en Using elementen zijn taalneutraal. Inlinetaken kunnen worden geschreven in Visual Basic of C#.

Opmerking

Elementen die door het Task element zijn opgenomen, zijn specifiek voor de taakfactory, in dit geval de codetaakfactory.

Code-element

Het laatste onderliggende element dat in het Task element moet worden weergegeven, is het Code element. Het Code element bevat of zoekt de code die u wilt compileren in een taak. Wat u in het Code element plaatst, is afhankelijk van hoe u de taak wilt schrijven.

Het Language kenmerk geeft de taal op waarin uw code is geschreven. Acceptabele waarden zijn cs voor C# vb voor Visual Basic.

Het Type kenmerk geeft het type code op dat in het Code element wordt gevonden.

  • Als de waarde Type is Class, bevat het Code element code voor een klasse die is afgeleid van de ITask interface.

  • Als de waarde Type is Method, definieert de code een onderdrukking van de Execute methode van de ITask interface.

  • Als de waarde Type is Fragment, definieert de code de inhoud van de Execute methode, maar niet de handtekening of de return instructie.

De code zelf wordt meestal weergegeven tussen een <![CDATA[ markering en een ]]> markering. Omdat de code zich in een CDATA-sectie bevindt, hoeft u zich geen zorgen te maken over het ontsnappen van gereserveerde tekens, bijvoorbeeld '<' of '>'.

U kunt ook het Source kenmerk van het Code element gebruiken om de locatie op te geven van een bestand dat de code voor uw taak bevat. De code in het bronbestand moet van het type zijn dat is opgegeven door het Type kenmerk. Als het Source kenmerk aanwezig is, is de standaardwaarde Type .Class Als Source deze niet aanwezig is, is Fragmentde standaardwaarde .

Opmerking

Wanneer u de taakklasse in het bronbestand definieert, moet de klassenaam overeenkomen met het TaskName kenmerk van het bijbehorende UsingTask-element .

HelloWorld

Hier volgt een voorbeeld van een eenvoudige inline-taak. De taak HelloWorld geeft 'Hallo, wereld!' weer op het standaardapparaat voor foutlogboekregistratie. Dit is meestal de systeemconsole of het venster Uitvoer van 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>

U kunt de HelloWorld-taak opslaan in een bestand met de naam HelloWorld.targets en deze vervolgens als volgt aanroepen vanuit een project.

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

Invoer- en uitvoerparameters

Inlinetaakparameters zijn onderliggende elementen van een ParameterGroup element. Elke parameter gebruikt de naam van het element dat het definieert. Met de volgende code wordt de parameter Textgedefinieerd.

<ParameterGroup>
  <Text />
</ParameterGroup>

Parameters kunnen een of meer van deze kenmerken hebben:

  • Required is een optioneel kenmerk dat standaard is false . Als true, dan is de parameter vereist en moet een waarde worden gegeven voordat de taak wordt aangeroepen.
  • ParameterType is een optioneel kenmerk dat standaard is System.String . Het kan worden ingesteld op elk volledig gekwalificeerde type dat een item of een waarde is die kan worden geconverteerd naar en van een tekenreeks met behulp van ChangeType. (Met andere woorden, elk type dat kan worden doorgegeven aan en van een externe taak.)
  • Output is een optioneel kenmerk dat standaard is false . Als true, moet de parameter een waarde krijgen voordat deze wordt geretourneerd uit de execute-methode.

Bijvoorbeeld

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

definieert deze drie parameters:

  • Expression is een vereiste invoerparameter van het type System.String.

  • Files is een vereiste invoerparameter voor de lijst met items.

  • Tally is een uitvoerparameter van het type System.Int32.

Als het Code element het Type kenmerk van Fragment of Methodheeft, worden eigenschappen automatisch gemaakt voor elke parameter. Anders moeten eigenschappen expliciet worden gedeclareerd in de broncode van de taak en moeten ze exact overeenkomen met de parameterdefinities.

Fouten opsporen in een inlinetaak

MSBuild genereert een bronbestand de inline-taak en schrijft de uitvoer naar een tekstbestand met een GUID-bestandsnaam in de map tijdelijke bestanden, AppData\Local\Temp\MSBuildTemp. De uitvoer wordt normaal gesproken verwijderd, maar om dit uitvoerbestand te behouden, kunt u de omgevingsvariabele MSBUILDLOGCODETASKFACTORYOUTPUT instellen op 1.

Voorbeeld 1

De volgende inlinetaak vervangt elk exemplaar van een token in het opgegeven bestand door de opgegeven waarde.

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

Voorbeeld 2

Met de volgende inlinetaak wordt geserialiseerde uitvoer gegenereerd. In dit voorbeeld ziet u het gebruik van een uitvoerparameter en een verwijzing.

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