Vytvoření vložené úlohy MSBuild pomocí RoslynCodeTaskFactory
Podobně jako CodeTaskFactory používá RoslynCodeTaskFactory kompilátory Roslyn pro různé platformy k vygenerování sestavení úloh v paměti pro použití jako vložené úlohy. Úlohy RoslynCodeTaskFactory cílí na .NET Standard a můžou pracovat na modulech runtime .NET Framework a .NET Core a také na jiných platformách, jako je Linux a macOS.
Poznámka:
RoslynCodeTaskFactory je k dispozici pouze v nástroji MSBuild 15.8 a vyšší. Verze NÁSTROJE MSBuild se řídí verzemi sady Visual Studio, takže roslynCodeTaskFactory je k dispozici v sadě Visual Studio 2017 verze 15.8 a vyšší.
Struktura vložené úlohy pomocí RoslynCodeTaskFactory
Vložené úlohy RoslynCodeTaskFactory jsou deklarovány stejným způsobem jako CodeTaskFactory, jediným rozdílem je, že cílí na .NET Standard. Vložený úkol a UsingTask
prvek, který ho obsahuje, jsou obvykle zahrnuty do souboru .targets a podle potřeby importovány do jiných souborů projektu. Tady je základní vložený úkol. Všimněte si, že nic nedělá.
<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>
Prvek UsingTask
v příkladu má tři atributy, které popisují úkol a vloženou úlohu továrnu, která ji zkompiluje.
Atribut
TaskName
v tomto případěDoNothing
pojmenuje úkol .Atributy
TaskFactory
pojmenují třídu, která implementuje vloženou úlohu factory.Atribut
AssemblyFile
poskytuje umístění vloženého objektu pro vytváření úloh. Případně můžete pomocí atributuAssemblyName
zadat plně kvalifikovaný název vložené třídy objektu pro vytváření úloh, která se obvykle nachází v globální mezipaměti sestavení (GAC).
Zbývající prvky DoNothing
úkolu jsou prázdné a jsou k dispozici pro ilustraci pořadí a struktury vloženého úkolu. Robustnější příklad je uveden dále v tomto tématu.
Prvek
ParameterGroup
je nepovinný. Při zadání deklaruje parametry pro úlohu. Další informace o vstupních a výstupních parametrech naleznete v části Vstupní a výstupní parametry dále v tomto tématu.Prvek
Task
popisuje a obsahuje zdrojový kód úkolu.Element
Reference
určuje odkazy na sestavení .NET, která používáte v kódu. To je ekvivalentem přidání odkazu na projekt v sadě Visual Studio. AtributInclude
určuje cestu odkazovaného sestavení.Tento
Using
prvek obsahuje seznam oborů názvů, ke kterým chcete získat přístup. Podobá seUsing
tomu příkaz v jazyce Visual C#. AtributNamespace
určuje obor názvů, který se má zahrnout.
Reference
a Using
prvky jsou nezávislé na jazyce. Vložené úlohy lze psát v některém z podporovaných jazyků .NET CodeDom, například v jazyce Visual Basic nebo Visual C#.
Poznámka:
Prvky obsažené v elementu Task
jsou specifické pro objekt pro vytváření úloh, v tomto případě objekt pro vytváření úloh kódu.
Prvek kódu
Posledním podřízeným prvkem, který se má objevit uvnitř elementu Task
Code
, je element. Prvek Code
obsahuje nebo vyhledá kód, který chcete zkompilovat do úkolu. To, co vložíte do elementu Code
, závisí na tom, jak chcete napsat úkol.
Atribut Language
určuje jazyk, ve kterém je váš kód napsán. Přijatelné hodnoty jsou cs
pro jazyk C# vb
pro Visual Basic.
Atribut Type
určuje typ kódu, který se nachází v elementu Code
.
Pokud je
Class
hodnotaType
, pakCode
prvek obsahuje kód pro třídu, která je odvozena z ITask rozhraní.Pokud je
Method
hodnotaType
, pak kód definuje přepsáníExecute
metody ITask rozhraní.Pokud je
Fragment
hodnotaType
, pak kód definuje obsahExecute
metody, ale ne podpis neboreturn
příkaz.
Samotný kód se obvykle zobrazuje mezi značkou <![CDATA[
a značkou ]]>
. Protože kód je v části CDATA, nemusíte se starat o únik vyhrazených znaků, například "<" nebo ">".
Případně můžete pomocí Source
atributu Code
elementu určit umístění souboru, který obsahuje kód pro váš úkol. Kód ve zdrojovém souboru musí být typu, který je určen atributem Type
. Source
Pokud atribut existuje, výchozí hodnota Type
je Class
. Pokud Source
není k dispozici, výchozí hodnota je Fragment
.
Poznámka:
Při definování třídy úkolu ve zdrojovém souboru musí název třídy souhlasit s TaskName
atributem odpovídajícího UsingTask elementu.
Hello World
Tady je robustnější vložený úkol s RoslynCodeTaskFactory. Úloha HelloWorld zobrazí "Hello, world!" na výchozím zařízení protokolování chyb, což je obvykle systémová konzola nebo okno Výstup sady Visual Studio. Prvek Reference
v příkladu je zahrnut pouze pro ilustraci.
<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>
Úkol HelloWorld můžete uložit do souboru s názvem HelloWorld.targets a pak ho vyvolat z projektu následujícím způsobem.
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="HelloWorld.targets" />
<Target Name="Hello">
<HelloWorld />
</Target>
</Project>
Vstupní a výstupní parametry
Vložené parametry úkolu jsou podřízené prvky elementu ParameterGroup
. Každý parametr přebírá název prvku, který ho definuje. Následující kód definuje parametr Text
.
<ParameterGroup>
<Text />
</ParameterGroup>
Parametry můžou mít jeden nebo více těchto atributů:
Required
je volitelný atribut, který jefalse
ve výchozím nastavení. Pokudtrue
je parametr povinný a musí být před voláním úkolu uvedena hodnota.ParameterType
je volitelný atribut, který jeSystem.String
ve výchozím nastavení. Může být nastaven na libovolný plně kvalifikovaný typ, který je buď položka nebo hodnota, která lze převést na řetězec pomocí System.Convert.ChangeType. (Jinými slovy, jakýkoli typ, který lze předat externímu úkolu a z externího úkolu.)Output
je volitelný atribut, který jefalse
ve výchozím nastavení. Pokudtrue
, pak parametr musí být před vrácením z Execute metoda.
Příklad:
<ParameterGroup>
<Expression Required="true" />
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>
definuje tyto tři parametry:
Expression
je povinný vstupní parametr typu System.String.Files
je povinný vstupní parametr seznamu položek.Tally
je výstupní parametr typu System.Int32.
Pokud prvek Code
má Type
atribut Fragment
nebo Method
, vlastnosti jsou automaticky vytvořeny pro každý parametr. V RoslynCodeTaskFactory, pokud Code
prvek má Type
atribut Class
, pak nemusíte zadávat ParameterGroup
, protože je odvozen ze zdrojového kódu (to je rozdíl od CodeTaskFactory
). V opačném případě musí být vlastnosti explicitně deklarovány ve zdrojovém kódu úlohy a musí přesně odpovídat jejich definici parametrů.
Příklad
Následující vložená úloha zaznamená některé zprávy a vrátí řetězec.
<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="cs">
<![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>
Tyto vložené úkoly mohou kombinovat cesty a získat název souboru.
<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="cs">
<![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="cs">
<![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>
Zajištění zpětné kompatibility
RoslynCodeTaskFactory
poprvé začal být k dispozici ve verzi 15.8 nástroje MSBuild. Předpokládejme, že máte situaci, kdy chcete podporovat předchozí verze sady Visual Studio a MSBuild, pokud RoslynCodeTaskFactory
nebyly dostupné, ale CodeTaskFactory
chcete použít stejný skript sestavení. Můžete použít Choose
konstruktor, který používá $(MSBuildVersion)
vlastnost k rozhodnutí v době sestavení, zda použít RoslynCodeTaskFactory
nebo se vrátit zpět CodeTaskFactory
, jako v následujícím příkladu:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<Choose>
<When Condition=" '$(MSBuildVersion.Substring(0,2))' >= 16 Or
('$(MSBuildVersion.Substring(0,2))' == 15 And '$(MSBuildVersion.Substring(3,1))' >= 8)">
<PropertyGroup>
<TaskFactory>RoslynCodeTaskFactory</TaskFactory>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TaskFactory>CodeTaskFactory</TaskFactory>
</PropertyGroup>
</Otherwise>
</Choose>
<UsingTask
TaskName="HelloWorld"
TaskFactory="$(TaskFactory)"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup />
<Task>
<Using Namespace="System"/>
<Using Namespace="System.IO"/>
<Code Type="Fragment" Language="cs">
<![CDATA[
Log.LogError("Using RoslynCodeTaskFactory");
]]>
</Code>
</Task>
</UsingTask>
<Target Name="RunTask" AfterTargets="Build">
<Message Text="MSBuildVersion: $(MSBuildVersion)"/>
<Message Text="TaskFactory: $(TaskFactory)"/>
<HelloWorld />
</Target>
</Project>