MSBuild beágyazott tevékenységek

Az MSBuild-feladatok általában egy olyan osztály összeállításával jönnek létre, amely implementálja a ITask felületet. További információ: Feladatok.

Ha el szeretné kerülni a lefordított tevékenységek létrehozásának többletterhelését, létrehozhat egy tevékenységet beágyazottan a projektfájlban vagy egy importált fájlban. A feladat üzemeltetéséhez nem kell külön szerelvényt létrehoznia. A beágyazott feladatokkal könnyebben nyomon követheti a forráskódot, és egyszerűbbé válik a feladat üzembe helyezése. A forráskód integrálva van az MSBuild projektfájlba vagy importált fájlba, általában egy .targets fájlba.

Beágyazott feladatot kódfeladat-előállítóval hozhat létre. Az aktuális fejlesztéshez ne a RoslynCodeTaskFactoryt használja.CodeTaskFactory CodeTaskFactory csak a 4.0-s verziójú C#-verziókat támogatja.

A beágyazott tevékenységek olyan kis feladatok kényelmét szolgálják, amelyek nem igényelnek bonyolult függőségeket. A beágyazott tevékenységek hibakeresési támogatása korlátozott. Ajánlott lefordított feladatot létrehozni beágyazott feladat helyett, ha összetettebb kódot szeretne írni, nuGet-csomagra hivatkozni, külső eszközöket futtatni, vagy olyan műveleteket végrehajtani, amelyek hibafeltételeket eredményezhetnek. A beágyazott feladatokat is minden buildeléskor lefordítja a rendszer, így észrevehető hatással lehet a build teljesítményére.

Beágyazott tevékenység felépítése

A beágyazott feladatokat egy UsingTask-elem tartalmazza. A beágyazott tevékenység és az UsingTask azt tartalmazó elem általában egy .targets fájlban van, és szükség szerint importálva van más projektfájlokba. Íme egy alapszintű beágyazott feladat, amely nem végez semmit, de a szintaxist szemlélteti:

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

A UsingTask példában szereplő elem három attribútummal rendelkezik, amelyek a feladatot és az azt fordító beágyazott feladat-előállítót írják le.

  • Ebben TaskName az esetben az attribútum neve a tevékenység. DoNothing

  • Az TaskFactory attribútum a beágyazott feladat-előállítót megvalósító osztálynak nevezi el.

  • Az AssemblyFile attribútum a beágyazott feladat-előállító helyét adja meg. Másik lehetőségként az AssemblyName attribútum használatával megadhatja a beágyazott feladat-előállító osztály teljes nevét, amely általában a fájlban $(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dlltalálható.

A tevékenység fennmaradó elemei DoNothing üresek, és a beágyazott tevékenységek sorrendjének és szerkezetének szemléltetésére szolgálnak. A cikk későbbi részében egy teljes példát mutatunk be.

  • Az ParameterGroup elem nem kötelező. Ha meg van adva, deklarálja a tevékenység paramétereit. A bemeneti és kimeneti paraméterekkel kapcsolatos további információkért lásd a cikk későbbi , bemeneti és kimeneti paramétereit .

  • Az Task elem leírja és tartalmazza a tevékenység forráskódját.

  • Az Reference elem a kódban használt .NET-szerelvényekre mutató hivatkozásokat adja meg. Ennek az elemnek a használata egyenértékű azzal, ha a Visual Studióban egy projektre mutató hivatkozást ad hozzá. Az Include attribútum a hivatkozott szerelvény elérési útját adja meg. Az mscorlib, a .NET Standard, a Microsoft.Build.Framework és a Microsoft.Build.Utilities.Core szerelvények, valamint a függőségként tranzitív módon hivatkozott szerelvények nem érhetők el Reference.

  • Az Using elem felsorolja a elérni kívánt névtereket. Ez az elem egyenértékű a using C# irányelvével. Az Namespace attribútum megadja a belefoglalandó névteret. Nem működik irányelv elhelyezése using a beágyazott kódban, mert a kód egy metódustörzsbe kerül, ahol using az irányelvek nem engedélyezettek.

Reference és Using az elemek nyelvi agnosztikusak. A beágyazott feladatok Visual Basic vagy C# nyelven is írhatók.

Megjegyzés:

Az elem által Task tartalmazott elemek a feladat-előállítóra, ebben az esetben a kód-feladat-előállítóra vonatkoznak.

Kódelem

Az elemen belül Task az utolsó gyermekelem az Code elem. Az Code elem tartalmazza vagy megkeresi a feladatba lefordítani kívánt kódot. Az elembe Code helyezett elemek attól függenek, hogyan szeretné megírni a feladatot.

Az Language attribútum azt a nyelvet határozza meg, amelyben a kód meg van írva. Az elfogadható értékek a cs C#, vb a Visual Basic esetében.

Az Type attribútum megadja az elemben Code található kód típusát.

  • Ha az érték Type az Class, akkor az Code elem egy olyan osztály kódját tartalmazza, amely a ITask felületből származik.

  • Ha az érték Type az Method, akkor a kód a felület metódusának Execute felülbírálását ITask határozza meg.

  • Ha az érték Type az Fragment, akkor a kód határozza meg a Execute metódus tartalmát, de az aláírást vagy az utasítást return nem.

Maga a kód általában egy jelölő és egy <![CDATA[]]> jelölő között jelenik meg. Mivel a kód egy CDATA-szakaszban található, nem kell aggódnia a fenntartott karakterek, például a "<" vagy a ">" elől.

Másik lehetőségként az Source elem attribútumával Code megadhatja a feladat kódját tartalmazó fájl helyét. A forrásfájl kódjának az attribútum által Type megadott típusnak kell lennie. Ha az Source attribútum jelen van, az alapértelmezett érték az TypeClass. Ha Source nincs jelen, az alapértelmezett érték a következő Fragment: .

Megjegyzés:

A feladatosztály forrásfájlban való definiálásakor az osztály nevének meg kell egyeznie a TaskName megfelelő UsingTask elem attribútumával.

HelloWorld

Íme egy példa egy egyszerű beágyazott feladatra. A HelloWorld feladat az alapértelmezett hibanaplózó eszközön jeleníti meg a "Hello, world!" szöveget, amely általában a rendszerkonzol vagy a Visual Studio Kimeneti ablaka.

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

A HelloWorld feladatot egy HelloWorld.targets nevű fájlba mentheti, majd meghívhatja egy projektből az alábbiak szerint.

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

Bemeneti és kimeneti paraméterek

A beágyazott tevékenységparaméterek egy ParameterGroup elem gyermekelemei. Minden paraméter az azt meghatározó elem nevét veszi fel. A paramétert Textaz alábbi kód határozza meg.

<ParameterGroup>
  <Text />
</ParameterGroup>

A paraméterek egy vagy több attribútummal rendelkezhetnek:

  • Required alapértelmezés szerint nem kötelező attribútum false . Ha true, akkor a paraméter megadása kötelező, és a feladat meghívása előtt meg kell adni egy értéket.
  • ParameterType alapértelmezés szerint nem kötelező attribútum System.String . Bármilyen teljesen minősített típusra állítható be, amely egy elem vagy egy olyan érték, amely sztringgé alakítható a használatával ChangeType. (Más szóval minden olyan típus, amely átadható egy külső tevékenységnek, és amelyből át lehet adni.)
  • Output alapértelmezés szerint nem kötelező attribútum false . Ha true, akkor a paraméternek meg kell adni egy értéket, mielőtt az Execute metódusból tér vissza.

Például

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

a következő három paramétert határozza meg:

  • Expression a System.String típusú kötelező bemeneti paraméter.

  • Files egy kötelező elemlista bemeneti paramétere.

  • Tally Egy System.Int32 típusú kimeneti paraméter.

Ha az Code elem attribútuma TypeFragment vagy Method, akkor a rendszer minden paraméterhez automatikusan létrehozza a tulajdonságokat. Ellenkező esetben a tulajdonságokat explicit módon deklarálni kell a tevékenység forráskódjában, és pontosan meg kell egyezniük a paraméterdefiníciókkal.

Beágyazott feladat hibakeresése

Az MSBuild létrehoz egy forrásfájlt a beágyazott feladathoz, és a kimenetet egy GUID fájlnévvel írja a szövegfájlba az Ideiglenes fájlok mappában( AppData\Local\Temp\MSBuildTemp). A kimenet általában törlődik, de a kimeneti fájl megőrzése érdekében a környezeti változót MSBUILDLOGCODETASKFACTORYOUTPUT 1 értékre állíthatja.

1. példa

Az alábbi beágyazott feladat az adott fájlban lévő tokenek minden előfordulását lecseréli a megadott értékre.

<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. példa

Az alábbi beágyazott feladat szerializált kimenetet hoz létre. Ez a példa egy kimeneti paraméter és egy hivatkozás használatát mutatja be.

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