Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Zadania programu MSBuild są zwykle tworzone przez kompilowanie klasy, która implementuje ITask interfejs. Aby uzyskać więcej informacji, zobacz Tasks.
Jeśli chcesz uniknąć nakładu pracy związanego z tworzeniem skompilowanego zadania, możesz utworzyć zadanie wbudowane w pliku projektu lub w zaimportowanym pliku. Nie musisz tworzyć oddzielnego zestawu do hostowania zadania. Użycie wbudowanego zadania ułatwia śledzenie kodu źródłowego i łatwiejsze wdrażanie zadania. Kod źródłowy jest zintegrowany z plikiem projektu MSBuild lub zaimportowanym plikiem, zazwyczaj plikiem .targets .
Tworzysz zadanie wbudowane, korzystając z fabryki zadań kodu. W przypadku bieżącego rozwoju trzeba używać RoslynCodeTaskFactory, a nie CodeTaskFactory.
CodeTaskFactory Obsługuje tylko wersje języka C# do wersji 4.0.
Zadania liniowe są przeznaczone dla małych zadań, które nie wymagają skomplikowanych zależności i są wygodne w użyciu. Obsługa debugowania dla zadań wbudowanych jest ograniczona. Zaleca się utworzenie skompilowanego zadania zamiast wbudowanego zadania, gdy chcesz napisać bardziej złożony kod, odwołać się do pakietu NuGet, uruchomić narzędzia zewnętrzne lub wykonać operacje, które mogą powodować błędy. Ponadto wbudowane zadania są kompilowane za każdym razem, gdy tworzysz, więc może to mieć zauważalny wpływ na wydajność kompilacji.
Struktura zadania wbudowanego
Zadanie inline jest zawarte w elemencie UsingTask. Zadanie w linii i element UsingTask, który je zawiera, są zazwyczaj uwzględniane w pliku .targets i importowane do innych plików projektu zgodnie z potrzebami. Oto podstawowe zadanie wbudowane, które nie wykonuje niczego, ale ilustruje składnię:
<!-- 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>
Element UsingTask w przykładzie ma trzy atrybuty opisujące zadanie i wbudowaną fabrykę zadań, która ją kompiluje.
Atrybut
TaskNamenazywa zadanie , w tym przypadkuDoNothing.Atrybut
TaskFactorynazywa klasę, która implementuje fabrykę zadań inline.Atrybut
AssemblyFilepodaje lokalizację zintegrowanej fabryki zadań. Alternatywnie można użyć atrybutuAssemblyName, aby określić w pełni kwalifikowaną nazwę klasy fabryki zadań inline, która zazwyczaj znajduje się w$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll.
Pozostałe elementy DoNothing zadania są puste i są udostępniane w celu zilustrowania kolejności i struktury zadania wbudowanego. Kompletny przykład zostanie przedstawiony w dalszej części tego artykułu.
Element
ParameterGroupjest opcjonalny. Gdy zostanie określony, deklaruje parametry zadania. Aby uzyskać więcej informacji na temat parametrów wejściowych i wyjściowych, zobacz Parametry wejściowe i wyjściowe w dalszej części tego artykułu.Element
Taskopisuje i zawiera kod źródłowy zadania.Element
Referenceokreśla odwołania do zestawów .NET używanych w kodzie. Użycie tego elementu jest równoważne do dodawania odwołania do projektu w programie Visual Studio. AtrybutIncludeokreśla ścieżkę przywołytowanego zestawu. Zestawy w mscorlib, .NET Standard, Microsoft.Build.Framework i Microsoft.Build.Utilities.Core, a także niektóre zestawy, które są tranzytywnie przywoływane jako zależności, są dostępne bez elementuReference.Element
Usingzawiera listę przestrzeni nazw, do których chcesz uzyskać dostęp. Ten element jest odpowiednikiemusingdyrektywy w języku C#. AtrybutNamespaceokreśla przestrzeń nazw do uwzględnienia. Nie można umieścić dyrektywyusingw kodzie wbudowanym, ponieważ ten kod znajduje się w treści metody, gdzie dyrektywyusingnie są dozwolone.
Reference i Using elementy są niezależne od języka. Zadania wbudowane można pisać w języku Visual Basic lub C#.
Uwaga / Notatka
Elementy zawarte w elemencie Task są specyficzne dla fabryki zadań, w tym przypadku fabryki zadań dla kodu.
Element kodu
Ostatnim elementem podrzędnym, który ma pojawić się w elemencie Task, jest element Code. Element Code zawiera lub lokalizuje kod, który chcesz skompilować w zadaniu. To, co umieścisz w elemenie Code , zależy od tego, jak chcesz napisać zadanie.
Atrybut Language określa język, w którym jest napisany kod. Dopuszczalne wartości to cs C#, vb dla języka Visual Basic.
Atrybut Type określa typ kodu, który znajduje się w elemecie Code .
Jeśli wartość
TypetoClass,Codeelement zawiera kod klasy pochodzącej z interfejsu ITask .Jeśli wartość
TypetoMethod, kod definiuje przesłonięcie metodyExecuteinterfejsu ITask.Jeśli wartość
TypetoFragment, kod definiuje zawartośćExecutemetody, ale nie podpis lub instrukcjęreturn.
Sam kod zwykle pojawia się między znacznikiem <![CDATA[ a znacznikiem ]]> . Ponieważ kod znajduje się w sekcji CDATA, nie musisz martwić się o ucieczkę zastrzeżonych znaków, na przykład "<" lub ">".
Alternatywnie możesz użyć Source atrybutu Code elementu, aby określić lokalizację pliku zawierającego kod zadania. Kod w pliku źródłowym musi być typu określonego przez atrybut Type.
Source Jeśli atrybut jest obecny, wartość domyślna to TypeClass. Jeśli Source nie ma wartości, wartość domyślna to Fragment.
Uwaga / Notatka
Podczas definiowania klasy zadań w pliku źródłowym nazwa klasy musi być zgodna z atrybutem TaskName odpowiedniego elementu UsingTask .
HelloWorld
Oto przykład prostego zadania wbudowanego. Zadanie HelloWorld wyświetla komunikat "Hello, world!" na domyślnym urządzeniu rejestrowania błędów, które jest zazwyczaj konsolą systemową lub oknem danych wyjściowych programu 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>
Zadanie HelloWorld można zapisać w pliku o nazwie HelloWorld.targets, a następnie wywołać je z projektu w następujący sposób.
<Project>
<Import Project="HelloWorld.targets" />
<Target Name="Hello">
<HelloWorld />
</Target>
</Project>
Parametry wejściowe i wyjściowe
Wbudowane parametry zadania to elementy podrzędne elementu ParameterGroup. Każdy parametr przyjmuje nazwę elementu, który go definiuje. Poniższy kod definiuje parametr Text.
<ParameterGroup>
<Text />
</ParameterGroup>
Parametry mogą mieć co najmniej jeden z następujących atrybutów:
-
Requiredjest opcjonalnym atrybutem, który jestfalsedomyślnie. Jeślitrueparametr jest wymagany i musi mieć wartość przed wywołaniem zadania. -
ParameterTypejest opcjonalnym atrybutem, który jestSystem.Stringdomyślnie. Można go ustawić na dowolny w pełni kwalifikowany typ, który jest elementem lub wartością, którą można przekonwertować na i z ciągu przy użyciu polecenia ChangeType. (Innymi słowy, dowolny typ, który można przekazać do i z zadania zewnętrznego). -
Outputjest opcjonalnym atrybutem, który jestfalsedomyślnie. Jeślitrue, wtedy parametr musi zostać podany wartość przed zwracaniem z metody Execute.
Na przykład
<ParameterGroup>
<Expression Required="true" />
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>
definiuje następujące trzy parametry:
Expressionjest wymaganym parametrem wejściowym typu System.String.Filesjest wymaganym parametrem wejściowym listy elementów.Tallyjest parametrem wyjściowym typu System.Int32.
Code Jeśli element ma Type atrybut Fragment lub Method, właściwości są tworzone automatycznie dla każdego parametru. W przeciwnym razie właściwości muszą być jawnie zadeklarowane w kodzie źródłowym zadania i muszą dokładnie odpowiadać ich definicjom parametrów.
Debugowanie zadania wbudowanego
Program MSBuild generuje plik źródłowy zadania wbudowanego i zapisuje dane wyjściowe w pliku tekstowym z nazwą pliku GUID w folderze plików tymczasowych AppData\Local\Temp\MSBuildTemp. Dane wyjściowe są zwykle usuwane, ale aby zachować ten plik wyjściowy, można ustawić zmienną środowiskową MSBUILDLOGCODETASKFACTORYOUTPUT na 1.
Przykład 1
Następujące zadanie wbudowane zastępuje każde wystąpienie tokenu w danym pliku daną wartością.
<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>
Przykład 2
Następujące zadanie wbudowane generuje serializowane dane wyjściowe. W tym przykładzie pokazano użycie parametru wyjściowego i odwołania.
<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>